summaryrefslogtreecommitdiff
path: root/docs/gtk_tut_it.sgml
diff options
context:
space:
mode:
authorPST 1998 Shawn T. Amundson <amundson@gimp.org>1998-03-12 18:23:11 +0000
committerShawn Amundson <amundson@src.gnome.org>1998-03-12 18:23:11 +0000
commitaffaf4f9d265522c71f1a9ba4b359094c00dc18a (patch)
tree2ed9182335ff959014320e46f7b1e1b76d27c39a /docs/gtk_tut_it.sgml
parent4f3495f955fb0798c18325c4d061891019e6b4f5 (diff)
downloadgdk-pixbuf-affaf4f9d265522c71f1a9ba4b359094c00dc18a.tar.gz
I just remembered this commit failed before because
of problems with the cvs server... connection timed out. Wed Mar 11 14:36:48 PST 1998 Shawn T. Amundson <amundson@gimp.org> * gtk/docs/: added tutorial, changed some files around to make more sense.
Diffstat (limited to 'docs/gtk_tut_it.sgml')
-rw-r--r--docs/gtk_tut_it.sgml8340
1 files changed, 8340 insertions, 0 deletions
diff --git a/docs/gtk_tut_it.sgml b/docs/gtk_tut_it.sgml
new file mode 100644
index 000000000..9ed24eb86
--- /dev/null
+++ b/docs/gtk_tut_it.sgml
@@ -0,0 +1,8340 @@
+
+<!doctype linuxdoc system>
+<article>
+<title>GTK Tutorial
+<author>Ian Main, <tt><htmlurl url="mailto:slow@intergate.bc.ca"
+ name="slow@intergate.bc.ca"></tt>
+
+<date>December 1, 1997 - Traduzione Aggiornata al 19 Gennaio 1998
+
+<abstract>Tradotto da Michel Morelli, <tt><htmlurl url="mailto:ziobudda@chiara.dei.unipd.it" name="ziobudda@chiara.dei.unipd.it"></tt>, Daniele Canazza, <tt><htmlurl url="mailto:dcanazz@tin.it" name="dcanazz@tin.it"></tt> e Antonio Schifano, <tt><htmlurl url="mailto:schifano@cli.di.unipi.it" name="schifano@cli.di.unipi.it"></tt>
+</abstract>
+
+<sect>Introduzione
+<p>
+GTK (GIMP Toolkit) era orginariamente sviluppato come toolkit per il programma
+GIMP (General Image Manipulation Program). GTK &egrave; costruito sulla base del
+kit di disegno di GIMP, il GDK (GIMP Drawing Kit) il quale &egrave; costruito a sua
+volta attorno alle funzioni della Xlib. E' chiamato ``toolkit di GIMP'' perch&eacute;
+era inizialmente scritto per sviluppare GIMP, ma ora viene utilizzato nello
+sviluppo di molti progetti software liberi. Gli autori sono
+<itemize>
+<item> Peter Mattis <tt><htmlurl url="mailto:petm@xcf.berkeley.edu"
+ name="petm@xcf.berkeley.edu"></tt>
+<item> Spencer Kimball <tt><htmlurl url="mailto:spencer@xcf.berkeley.edu"
+ name="spencer@xcf.berkeley.edu"></tt>
+<item> Josh MacDonald <tt><htmlurl url="mailto:jmacd@xcf.berkeley.edu"
+ name="jmacd@xcf.berkeley.edu"></tt>
+</itemize>
+
+<p>
+GTK &egrave; essenzialmente una API (application programmers interface)
+orientata agli oggetti.
+Anche se scritto completamente in C, &egrave; implementato usando l'idea delle
+classi e delle funzioni di callback (puntatori a funzioni).
+
+<p>
+C'&egrave; anche una terza componente chiamata glib che contiene una serie di
+implementazioni differenti di alcune chiamate di funzioni standard e anche
+alcune funzioni aggiuntive, per esempio per la manipolazione delle liste
+collegate, eccetera. Le funzioni sostitutive sono usate per migliorare la
+portabilit&agrave; di GTK. Alcune delle funzioni implementate qui non sono
+disponibili o non sono standard, altre sono uniche come g_strerror().
+Altre contengono miglioramenti alle stesse della libc come g_malloc che ha
+delle utility di debugging migliorate.
+
+<p>
+Questo tutorial &egrave; un tentativo di documentare il meglio possibile la libreria gtk
+e non pretende di essere completo. Questo tutorial suppone una buona conoscenza del
+linugaggio C e di come creare programmi in C. Saranno facilitati i lettori che hanno una
+precedente esperienza nella programmazione in X. Se il GTK &egrave; il primo insieme di widget
+che studiate, siete pregati di dirmi come avete trovato questo tutorial e che tipo di problemi
+avete avuto.
+Notate che c'&egrave; anche una versione per il C++ della libreria GTK (chiamata GTK--), quindi
+se preferite utilizzare questo linguaggio al posto del C potreste cercare questa versione
+e non la GTK normale.
+Ci sono poi un ``wrapper'' Objective C e un collegamento a Guile, ma non ne seguo
+l'evoluzione.
+
+<p>
+Mi farebbe molto piacere conoscere qualsiasi problema che abbiate avuto nell'imparare il GTK
+da questo documento e apprezzerei anche critiche sul come migliorarlo.
+
+<sect>Iniziamo
+<p>
+La prima cosa da fare &egrave; certamente quella di scaricare il GTK e installarlo. Potete prendere
+l'ultima versione dal sito ftp.gimp.org nella directory /pub/gimp. Un'altra possibile sorgente
+di informazioni &egrave; il sito http://www.gimp.org/gtk. GTK usa il comando GNU autoconf per
+autoconfigurarsi.
+Una volta estratti i file dall'archivio tar, eseguite configure --help per vedere una lista delle
+opzioni del comando configure.
+
+<p>
+Per iniziare la nostra introduzione a GTK, cominceremo con il pi&ugrave; semplice programma
+possibile . Questo programma crea una finestra con dimensioni (in pixel) di 200x200 e
+l'unica possibilit&agrave; di uscita &egrave; di ucciderlo ucciso usando la shell o il Window Manager.
+
+<tscreen><verb>
+#include <gtk/gtk.h>
+
+int main (int argc, char *argv[])
+{
+ GtkWidget *window;
+
+ gtk_init (&amp;argc, &amp;argv);
+
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ gtk_widget_show (window);
+
+ gtk_main ();
+
+ return 0;
+}
+</verb></tscreen>
+
+Tutti i programmi certamente includeranno &lt;gtk/gtk.h&gt; che dichiara le variabili, le funzioni,
+le strutture, etc. che saranno usate nella tua applicazione GTK.
+
+<p>
+La linea seguente:
+
+<tscreen><verb>
+gtk_init (&amp;argc, &amp;argv);
+</verb></tscreen>
+
+invoca la funzione gtk_init(gint *argc, gchar ***argv) che sar&agrave; usata in tutte le
+applicazioni GTK. Questa funzione sistema alcune cose al posto nostro, come la visuale
+predefinita e la mappa dei colori, e procede poi chiamando gdk_init(gint *argc, gchar ***argv).
+Questa funzione inizializza la libreria per l'uso, setta il gestore predefinito dei segnali
+e guarda negli argomenti, passati via linea di comando alla tua applicazione, alla ricerca
+di uno di questi argomenti:
+<itemize>
+<item> <tt/--display/
+<item> <tt/--debug-level/
+<item> <tt/--no-xshm/
+<item> <tt/--sync/
+<item> <tt/--show-events/
+<item> <tt/--no-show-events/
+</itemize>
+<p>
+Rimuove questi argomenti dalla lista degli argomenti passati, lasciando quelli non
+riconosciuti a disposizione della tua applicazione che potr&agrave; tenerne conto o ignorarli.
+In questo modo si crea un set di argomenti standard accettato da tutte le applicazione GTK.
+
+<p>
+Le seguenti 2 linee di codice creano e mostrano la finestra.
+
+<tscreen><verb>
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ gtk_widget_show (window);
+</verb></tscreen>
+
+L'argomento GTK_WINDOW_TOPLEVEL specifica che noi vogliamo che la nostra finestra si
+sottometta alle decorazioni del windows manager e alla posizione che quest'ultimo indicher&agrave;.
+Invece di creare una finestra avente dimensioni 0x0, la dimensione di una finestra senza
+figli (altri widget, come i bottoni, etc) &egrave; predefinita a 200x200 cos&igrave; che si possa manipolarla.
+La funzione gtk_widget_show() fa s&igrave; che GTK sappia che abbiamo finito di settare gli
+attributi di questo widget e che quindi quest'ultimo pu&ograve; essere visualizzato.
+
+<p>
+L'ultima linea ci fa entrare nel ciclo principale del GTK.
+
+<tscreen><verb>
+gtk_main ();
+</verb></tscreen>
+
+gtk_main() &egrave; un'altra chiamata che tu vedrete in tutte le applicazioni GTK. Quando il controllo
+raggiunge questo punto, l'applicazione si metter&agrave; a dormire aspettando che si verifichino eventi
+di X (come la pressione di un bottone o di un tasto), timeout o notifiche di Input/Output dei file
+Nel nostro esempio, comunque, tutti gli eventi sono ignorati.
+
+<sect1>Hello World in GTK
+<p>
+Ok, ora un programma con un widget (un bottone). E' il classico ``Hello World'' alla GTK.
+
+<tscreen><verb>
+
+#include <gtk/gtk.h>
+
+
+/* E' una funzione di ritorno (callback). Gli argomenti passati sono ignorati in questo
+* esempio.
+* Piu' informazioni sulle callback in seguito. */
+
+void hello (GtkWidget *widget, gpointer data)
+{
+ g_print ("Hello World\n");
+}
+
+gint delete_event(GtkWidget *widget, gpointer data)
+ {
+ g_print ("delete event occured\n");
+ /* Se si d&agrave; TRUE al manipolatore del segnale ``delete_event'', GTK emettera' il segnale
+ ``destroy''. Fornire FALSE significa non volere che la finestra sia distrutta.
+ Cambia FALSE con TRUE e la finestra principale sara' distrutta con un "delete_event"
+ */
+
+/* Un'altra callback */
+void destroy (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;
+
+ /* Questa e' una chiamata presente in tutte le applicazioni GTK. Gli argomenti della
+ linea di comando vengono scorsi e restituiti alla applicazione */
+ gtk_init (&amp;argc, &amp;argv);
+
+ /* Crea una nuova finestra */
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+
+ /* Quando alla finestra viene passato il segnale ``delete_event'' (questo
+ * segnale viene passato Windows Manager di solito con l'opzione 'close'
+ * o con la barra del titolo (title bar)) noi chiediamo che la funzione
+ * delete_event() (definita sopra) venga invocata.
+ * Il dato passato come argomento alla funzione di ritorno &eacute; NULL
+ * ed &eacute; ignorato dalla funzione stessa. */
+ gtk_signal_connect (GTK_OBJECT (window), "delete_event",
+ GTK_SIGNAL_FUNC (destroy), NULL);
+
+ /* Qui connettiamo l'evento ``destroy'' al gestore del segnale.
+ * Questo evento accade quando noi chiamimo la funzione gtk_widget_destroy()
+ * sulla finestra o se ritorniamo TRUE dalla callback ``delete_event''. */
+ gtk_signal_connect (GTK_OBJECT (window), "destroy",
+ GTK_SIGNAL_FUNC (destroy), NULL);
+
+ /* Setta il bordo interno della finestra */
+ gtk_container_border_width (GTK_CONTAINER (window), 10);
+
+ /* Crea un nuovo bottone avente etichetta (label) uguale a ``Hello World'' */
+ button = gtk_button_new_with_label ("Hello World");
+
+ /* Quando il bottone riceve il segnale ``clicked'', invochera' la funzione
+ * hello() passando NULL come argomento della funzione. La funzione
+ * hello() &eacute; definita sopra. */
+ gtk_signal_connect (GTK_OBJECT (button), "clicked",
+ GTK_SIGNAL_FUNC (hello), NULL);
+
+ /* Questo far&agrave; s&igrave; che la finestra venga distrutta dalla chiamata
+ * gtk_widget_destroy(window) quando il bottone verr&agrave; premuto. Ancora,
+ * questo segnale (``destroy'') puo' arrivare da qui o dal windows
+ * manager */
+ gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
+ GTK_SIGNAL_FUNC (gtk_widget_destroy),
+ GTK_OBJECT (window));
+
+ /* Questo inserisce il bottone nella finestra
+ * (un contenitore GTK) */
+ gtk_container_add (GTK_CONTAINER (window), button);
+
+ /* Il passo finale &eacute; il mostrare questo nuovo widget appena creato */
+ gtk_widget_show (button);
+
+ /* e la finestra */
+ gtk_widget_show (window);
+
+ /* Tutte le applicazioni GTK devono avere la funzione gtk_main().
+ * Il controllo finisce qui e attende un evento (come la pressione
+ * di un tasto o l'evento di un mouse).
+ gtk_main ();
+
+ return 0;
+}
+</verb></tscreen>
+
+<sect1>Compilare hello World
+<p>
+Per compilare si utilizza :
+
+<tscreen><verb>
+gcc -Wall -g helloworld.c -o hello_world -L/usr/X11R6/lib \
+ -lglib -lgdk -lgtk -lX11 -lXext -lm
+</verb></tscreen>
+<p>
+Le librerie sopra (glib, gtk,...) devono essere tutte nel percorso predefinito
+delle librerie. Se cosi' non fosse aggiungi ``-L&lt;directory&gt;'' e il gcc
+guarder&agrave; in questa directory per cercare le librerie di cui necessita.
+Per esempio sul mio sistema debian-linux io ho dovuto aggiungere
+<tt>-L/usr/X11R6/lib</> per riuscire a far trovare le librerie di X11.
+
+<p>
+L'odine della dichiarazione delle librerie &eacute; significativo. Il linker
+sa quali funzioni di una libreria ha bisogno prima di processarla.
+
+<p>
+le librerie che noi linkiamo sono:
+<itemize>
+<item> la libreria glib (-lglib), contiene varie funzioni, ma solo
+g_print() &eacute; usato in questo esempio. GTK si appoggia a questa
+libreria cosi' devi sempre, comunque, linkarla. Vedi comunque la <ref
+id="sec_glib" name="glib"> sezione sulla glib per altri dettagli.
+<item>La libreria GDK (-lgdk), la copertura della X11.
+<item>La libreria GTK (-lgtk), la libreria dei widget, basata sulla GDK.
+<item>La libreria xlib(-lX11) la quale &egrave; usata dalla GDK.
+<item>La libreria Xext(-lXext). Questa contiene il codice per le pixmap a
+memoria condivisa e altre estensioni di X.
+<item>La libreria matematica (-lm). Questa &eacute; usata dalla GTK per vari scopi.
+</itemize>
+
+<sect1>Teoria dei segnali e delle funzioni di ritorno (callback)
+<p>
+Prima di guardare in dettaglio ``Hello World'', discuteremo gli eventi e le
+funzioni di ritorno. GTK &egrave; un toolkit guidato dagli eventi, il che significa
+che se ne star&agrave; a dorimire in gtk_main finch&eacute; non succeder&agrave; un evento ed il
+controllo passer&agrave; alla funzione appropriata.
+
+<p>
+Questo passaggio di controllo &egrave; fatto usando l'idea dei segnali. Quando succede un
+evento, come la pressione di un bottone del mouse, verr&agrave; emesso il segnale appropriato
+dal widget che &eacute; stato premuto.
+Questo &egrave; il modo in cui GTK fa molto del suo utile lavoro. Per fare s&igrave; che un
+bottone esegua una azione, noi prepareremo un gestore del segnale che catturi
+questi segnali e chiami la funzione corretta. Questo &egrave; fatto usando una
+funzione del tipo:
+
+<tscreen><verb>
+gint gtk_signal_connect (GtkObject *object,
+ gchar *name,
+ GtkSignalFunc func,
+ gpointer func_data);
+</verb></tscreen>
+
+<p>
+Dove, il primo argomento &egrave; il widget che emetter&agrave; il segnale, il secondo &egrave; il nome
+del segnale che si vuole catturare,il terzo &egrave; la funzione che verr&agrave; invocata
+quando il segnale sar&agrave; catturato e il quarto &egrave; il dato che potr essere passato a
+questa funzione.
+
+<p>
+La funzione specificata come terzo argomento &egrave; chiamata ``funzione di ritorno (callback)'',
+e dovrebbe essere della forma:
+
+<tscreen><verb>
+void callback_func(GtkWidget *widget, gpointer *callback_data);
+</verb></tscreen>
+<p>
+Dove il primo argomento sar&agrave; un puntatore al widget che emette il segnale e il
+secondo un puntatore al dato passato come ultimo argomento della funzione
+gtk_signal_connect() come descritto sopra.
+
+<p>
+Un'altra chiamata usata nell'esempio Hello World &egrave;:
+
+<tscreen><verb>
+gint gtk_signal_connect_object (GtkObject *object,
+ gchar *name,
+ GtkSignalFunc func,
+ GtkObject *slot_object);
+</verb></tscreen>
+<p>
+gtk_signal_connect_object() &egrave; uguale a gtk_signal_connect() eccetto che la
+funzione di callback usa solo un argomento, un puntatore ad un'oggetto GTK.
+Cosi' quando usa questa funzione per connettere i segnali, la callback
+potrebbe essere della forma :
+
+<tscreen><verb>
+ void callback_func (GtkObject *object);
+</verb></tscreen>
+<p>
+Dove object &egrave; di solito un widget. Noi, generalmente, non assegnamo una callback per
+gtk_signal_connect_object. Queste sono invocate ,usualmente, per chiamare
+una funzione GTK che accetta un widget singolo o un oggetto come argomento,
+come nel caso dell'esempio Hello World.
+
+Lo scopo di avere due funzioni per connettere i segnali &egrave; semplicemente quello di
+permettere alla funzione di callback di avere un numero di argomenti diverso.
+Molte funzioni della libreria GTK accettano solo un singolo puntatore ad un widget
+GTK come argomento, cos&igrave; per queste si pu&ograve; usare la funzione gtk_signal_connect_object(),
+mentre per le vostre funzioni potreste aver bisogno di passare dati supplementari alle
+funzioni di ritorno.
+
+<sect1>Attraverso Hello World passo per passo
+<p>
+Ora che conosciamo la teoria che vi &egrave; dietro, iniziamo ad essere pi&ugrave; chiari
+camminando attraverso il programma di Hello World.
+
+<p>
+Questa &egrave; la funzione di callback che sar&agrave; invocata quando il bottone &egrave; clickato.
+Noi, in questo esempio, ignoriamo sia il widget che i dati passati, ma non &egrave;
+difficile farci invece qualcosa. Il prossimo esempio user&agrave; l'argomento passato
+per dire quale bottone &egrave; stato premuto.
+
+<tscreen><verb>
+void hello (GtkWidget *widget, gpointer *data)
+{
+ g_print ("Hello World\n");
+}
+</verb></tscreen>
+
+<p>
+Questa callback &egrave; un po' speciale. L'evento ``delete'' avviene quanto il Window Manager
+manda questo evento all'applicazione. Qui abbiamo una scelta da fare: cosa fare di questo evento.
+Possiamo ignorarlo, creare qualche tipo di risposta, o semplicemente terminare
+l'applicazione.
+
+Il valore che si restituisce in questa callback fa s&igrave; che la GTK sappia cosa fare.
+Restituire FALSE significa che noi non vogliamo che il segnale ``destroy'' sia emesso,
+quindi far s&igrave; che la nostra applicazione continui a procedere. Ritornare TRUE vuole dire
+far emettere il segnale ``destroy'' il quale chiamer&agrave; il gestore del segnale ``destroy''
+(o meglio : la nostra funzione di callback).
+
+<tscreen><verb>
+ gint delete_event(GtkWidget *widget, gpointer data)
+ {
+ g_print ("delete event occured\n");
+
+ return (FALSE);
+ }
+</verb></tscreen>
+
+<p>
+Questa &egrave; un'altra funzione di callback la quale fa uscire dal programma chiamando
+gtk_main_quit(). Non c'&egrave; molto da dire al riguardo, &egrave; abbastanza auto-esplicativa.
+
+<tscreen><verb>
+void destroy (GtkWidget *widget, gpointer *data)
+{
+ gtk_main_quit ();
+}
+</verb></tscreen>
+<p>
+Ritengo che conosciate la funzione main()... si, come tutte le altre applicazioni
+anche le applicazioni GTK hanno questa funzione.
+
+<tscreen><verb>
+int main (int argc, char *argv[])
+{
+</verb></tscreen>
+
+<p>
+Questa parte dichiara un puntatore ad una struttura di tipo GtkWidget. Queste sono
+usate sotto per creare una finestra ed un bottone.
+
+<tscreen><verb>
+ GtkWidget *window;
+ GtkWidget *button;
+</verb></tscreen>
+<p>
+Qui vi &egrave; ancora la nostra gtk_init. Come prima questa inizializza il toolkit e
+analizza gli argomenti trovati nella linea di comando_ Tutti gli argomenti riconosciuti
+nella linea di comando sono rimossi dalla lista degli argomenti e vengono cos&igrave; modificati
+argc e argv per far s&igrave; che sembri che questi non siano mai esisitie permettere alla
+tua applicazione di analizzare gli argomenti rimasti.
+
+<tscreen><verb>
+ gtk_init (&amp;argc, &amp;argv);
+</verb></tscreen>
+<p>
+Crea una nuova finestra. Questo viene spiegato abbastanza approfonditamente pi&ugrave; avanti.
+Viene allocata la memoria per la struttura GtkWidget *window cos&igrave; che si punti ad una struttura
+valida. In questo modo si predispone la nuova finestra, ma non la si visualizza fino a sotto dove, quasi
+alla fine del nostro programma, invochiamo gtk_widget_show(window).
+<tscreen><verb>
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+</verb></tscreen>
+<p>
+Questo &egrave; un esempio di come connettere un gestore dei segnali con un oggetto, in questo
+caso la finestra. Qui viene catturato il segnale ``destroy''. Questo &egrave; emesso quando usiamo
+il Window Manager per uccidere la finestra (e noi restituiamo TRUE dal gestore di ``delete_event'')
+o quando emettiamo la chiamata gtk_widget_destroy() passando l'oggetto finestra
+come oggetto da distruggere. Sistemando le cose cos&igrave;, trattiamo entrambi i casi con una singola
+chiamata. Qui &egrave; giusto invocare la funzione destroy() definita sopra con NULL come argomento,
+la quale termina l'applicazione GTK per noi.
+Questo ci permetter&agrave; di utilizzare il Window Manager per uccidere il programma.
+<!-- fino a qui -->
+<p>
+GTK_OBJECT e GTK_SIGNAL_FUNC sono macro che interpretano il casting e il controllo di tipo per noi,
+cos&igrave; da rendere piu' leggibile il codice.
+
+<tscreen><verb>
+ gtk_signal_connect (GTK_OBJECT (window), "destroy",
+ GTK_SIGNAL_FUNC (destroy), NULL);
+</verb></tscreen>
+<p>
+La prossima funzione &egrave; usata per settare un attributo di un oggetto contenitore. Questo
+sistema la finestra cos&igrave; da avere un'area vuota all'interno della finestrra larga 10 pixel dove
+non potr&agrave; andare nessun widget. Ci sono altre funzioni simili che vedremo nella
+sezione <ref id="sec_setting_widget_attributes" name="Settare gli attributi del Widget.">
+
+<p>
+E ancora, GTK_CONTAINER &egrave; una macro per interpretare il casting di tipo.
+
+<tscreen><verb>
+ gtk_container_border_width (GTK_CONTAINER (window), 10);
+</verb></tscreen>
+<p>
+Questa chiamata crea un nuovo bottone. Alloca spazio in memoria per un nuovo GtkWidget,
+inizializzandolo e facendo s&igrave; che il puntatore a bottone punti ad esso.
+Quando sar&agrave; visualizzato, avr&agrave; etichetta ``Hello World''.
+
+<tscreen><verb>
+ button = gtk_button_new_with_label ("Hello World");
+</verb></tscreen>
+<p>
+Qui prendiamo il bottone e gli facciamo fare qualcosa di utile.
+Gli colleghiamo un un gestore di segnale in modo che quando emetter&agrave; il
+segnale ``clicked'', verr&agrave; invocata la nostra funzione hello(). Il dato passato
+alla funzione &egrave; ignorato, cosicch&eacute; alla funzione di callback hello() passiamo
+semplicemente NULL. Evidentemente il segnale ``clicked'' viene emesso quando
+premiamo il bottone con il mouse.
+
+<tscreen><verb>
+ gtk_signal_connect (GTK_OBJECT (button), "clicked",
+ GTK_SIGNAL_FUNC (hello), NULL);
+</verb></tscreen>
+<p>
+Usiamo questo bottone anche per uscire dal programma. Questo illustrera'
+come il segnale ``destroy'' pu&ograve; arrivare sia dal Window Manager che dal nostro programma.
+Quando il bottone &egrave; ``clicked'', come sopra, chiamera' la funzione di callback
+hello() e poi questa nell'ordine in cui sono definite. Si possono avere
+tante funzioni di callback, quante sono necessarie, e saranno eseguite nell'ordine in cui
+sono connesse. Visto che la funzione gtk_widget_destroy() accetta come argomento solo un
+GtkWidget *widget, usiamo la funzione gtk_signal_connect_object()
+al posto della semplice gtk_signal_connect().
+
+<tscreen><verb>
+ gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
+ GTK_SIGNAL_FUNC (gtk_widget_destroy),
+ GTK_OBJECT (window));
+</verb></tscreen>
+<p>
+Questa &eacute; una chiamata di ``impacchettamento'' che sar&agrave; spiegata pi&ugrave; avanti.
+Ma &egrave; molto facile da capire. Semplicemente dice alla libreria GTK che il
+bottone &egrave; da mettere nella finestra dove sar&agrave; visualizzato.
+
+<tscreen><verb>
+ gtk_container_add (GTK_CONTAINER (window), button);
+</verb></tscreen>
+<p>
+A questo punto abbiamo predisposto tutto quello che ci eravamo prefissati.
+Con tutti i gestori di segnale a posto e il bottone messo nella finestra in cui
+dovrebbe essere, possiamo dire a GTK di mostrare gli oggetti sullo schermo.
+L'oggetto finestra viene mostrato per ultimo cos&igrave; che la finestra completa di tutti
+i suoi oggetti sar&agrave; mostrata in una volta sola, invece di vedere
+prima la finestra spoglia e poi la comparsa del bottone all'interno di essa.
+Per quanto, con questi semplici esempi, questo l'avrai gi&agrave; notato.
+<tscreen><verb>
+ gtk_widget_show (button);
+
+ gtk_widget_show (window);
+</verb></tscreen>
+<p>
+E naturalmente chiamiamo gtk_main(), la quale aspetta l'arrivo degli eventi
+dal server X e chiamer&agrave; l'oggetto interessato per fargli emettere il segnale
+adeguato.
+<tscreen><verb>
+ gtk_main ();
+</verb></tscreen>
+E il return finale. Il controllo ritorna qui dopo che viene invocata gtk_quit().
+
+<tscreen><verb>
+ return 0;
+</verb></tscreen>
+<p>
+Ora, quando premiamo il bottone del mouse su un bottone GTK, questo oggetto
+emette il segnale ``clicked''. Per poter utilizzare queste informazioni, il nostro
+programma predispone un gestore di segnale per catturare quel segnale, il quale
+avvia la funzione da noi scelta. Nel nostro esempio, quando il bottone creato viene
+clickato , la funzione hello() &egrave; invocata con un argomento NULL, dopoodich&eacute;
+viene invocato il successivo gestore di questo segnale. Questo chiama la funziona
+gtk_widget_destroy(), passandole l'oggetto-finestra (window) come argomento, che
+distrugger&agrave; la finestra. Questo fa s&igrave; che la finestra emetta il segnale
+``destroy'' che viene catturato e che fa invocare la funzione di ritorno
+destroy(), che semplicemente esce dal programma GTK.
+
+<p>
+Un'altro modo in cui possono andare le cose &egrave; l'uso del window manager per uccidere
+la finestra. Questo causera' l'emissione del segnale ``delete_event'' che
+automaticamente chiamer&agrave; il gestore del segnale ``delete_event''. Se qui noi
+restituiamo il valore FALSE, la finestra non verr&agrave; toccata e tutto proceder&agrave; come
+se nulla fosse successo. Dare invece il valore TRUE causer&agrave; l'emissione da parte
+di GTK del segnale ``destroy'' il quale, a sua volta, invocher&agrave; la callback ``destroy'',
+uscendo dall'applicazione.
+
+<p>
+Nota che questi segnali non sono gli stessi del sistema Unix e che non sono
+implementati usando quei segnali, anche se la terminologia &egrave; praticamente identica.
+
+<sect>Proseguiamo
+<p>
+<sect1>Tipi di Dato
+<p>
+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
+riferiti rispettivamente a int e char. Questo viene fatto per rimediare alla brutta
+dipendenza dalle dimensioni di semplici tipi di dato quando si fanno dei calcoli.
+Un buon esempio &egrave; ``gint32'' il quale sar&agrave; un tipo di dato riferito ad un intero a
+32 bit per tutte le piattaforme x86 e ad un 64 bit per gli alpha.
+I tipi di dato sono ben spiegati pi&ugrave; avanti ed intuitivi. Sono definiti in
+glib/glib.h (il quale viene incluso da gtk.h).
+
+<p>
+Noterete anche la possibilit&agrave; di utilizzare un GtkWidget quando la funzione richiede
+un GtkObject. GTK &egrave; una libreria orienta agli oggetti ed un widget &egrave; un oggetto.
+
+<sect1>Altri Dettagli sui Segnali
+<p>
+Diamo un'altra occhiata alla dichiarazione della funzione gtk_signal_connect.
+
+<tscreen><verb>
+gint gtk_signal_connect (GtkObject *object, gchar *name,
+ GtkSignalFunc func, gpointer func_data);
+</verb></tscreen>
+Notate il valore di ritorno definito come gint? questo &egrave; un identificatore per
+la tua funzione di callback. Come detto sopra, si possono avere pi&ugrave; funzioni di
+ritorno per ogni segnale e per ogni ogetto a seconda delle necessit&agrave;. ed ognuna sar&agrave;
+eseguita in sequenza, nell'ordine in cui sono state collegate. Questo identificatore
+ti permette di rimuovere una funzione dalla lista delle funzioni di ritorno tramite
+la seguente chiamata
+<tscreen><verb>
+void gtk_signal_disconnect (GtkObject *object,
+ gint id);
+</verb></tscreen>
+Cos&igrave; passando il widget da cui vuoi rimuovere il gestore di segnale, e
+l'identificativo restituito da una delle funzioni signal_connect, puoi rimuovere
+il gestore di segnale che desideri da quella del widget.
+
+<p>
+Un'altra funzione per rimuovere tutti i segnali di un widget in una volta sola &egrave;:
+
+<tscreen><verb>
+gtk_signal_handlers_destroy (GtkObject *object);
+</verb></tscreen>
+<p>
+Questa chiamata &egrave; abbastanza auto esplicativa. Semplicemente rimuove tutti i segnali
+collegati al widget che passi alla funzione come argomento.
+
+<sect1>Miglioriamo Hello World
+
+<p>
+Diamo un'occhiata ad una migliorata versione di Hello World con altri esempi sulle
+callback. Questo anche ci introdurr&agrave; al nostro prossimo argomento,
+l'impacchettamento dei widget.
+
+<tscreen><verb>
+#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 (&amp;argc, &amp;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 &egrave; descritta
+ dettagliatamente nella sezione "packing". La scatola non &egrave; realmente
+ visibile, &egrave; 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;
+}
+</verb></tscreen>
+<p>
+Compilate questo programma usando gli stessi argomenti di link del nostro primo
+esempio. Noterete che questa volta non c'&egrave; 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 &egrave; 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.
+
+<p>
+Solo una piccola nota, c'&egrave; 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.
+
+<sect>Come ``Impacchettare'' i Widget
+<p>
+Nel momento in cui si crea un'applicazione, normalmente si avr&agrave; la necessit&agrave; di mettere pi&ugrave;
+di un unico bottone all'interno di una finestra. Il nostro primo esempio ``Hello World''
+usava un solo oggetto, cosicch&eacute; abbiamo potuto usare semplicemente una chiamata
+a gtk_container_add per impacchettare il widget nella finestra. Quando invece si vuole
+inserire pi&ugrave; di un unico widget in una finestra, come si fa a controllare dove vengono
+posizionati i propri oggetti? E' qui che entra in gioco il meccanismo dell'``impacchettamento''.
+<sect1>Teoria delle Scatole per Impacchettamento
+<p>
+La maggior parte dell'impacchettamento viene effettuata creando delle scatole
+come nell'esempio pi&ugrave; sopra. Le scatole sono dei contenitori invisibili di
+widget che possiamo usare per imballarci i nostri oggetti e che esistono in
+due variet&agrave;: in particolare si possono avere scatole orizzontali (hbox) e
+verticali (vbox).
+Quando si impacchentano degli oggetti in una scatola orizzontale, gli oggetti vengono inseriti
+orizzontalmente da sinistra a destra oppure da destra a sinistra a seconda della
+chiamata di funzione che si usa. In una scatola verticale, gli oggetti vengono inseriti
+dall'alto in basso o viceversa. Si pu&ograve; usare qualsiasi combinazione di scatole
+all'interno o a fianco di altre scatole, fino ad ottenere l'effetto desiderato.
+<p>
+Per creare una nuova scatola orizzontale, si usa una chiamata a gtk_hbox_new(), mentre
+per le scatole verticali si usa gtk_vbox_new(). Per inserire i widget
+all'interno di questi contenitori si usano le funzioni gtk_box_pack_start() e
+gtk_box_pack_end(). La funzione gtk_box_pack_start() comincer&agrave; dall'alto verso il
+basso in una vbox e da sinistra a destra in una hbox. gtk_box_pack_end() fa l'opposto,
+impacchettando dal basso verso l'alto in una vbox e da destra a sinistra in una hbox.
+Queste funzioni ci permettono di giustificare a destra o a sinistra i nostri
+widget, e possono essere mescolate in qualsiasi modo per ottenere l'effetto desiderato.
+Useremo gtk_box_pack_start() nella maggior parte dei nostri esempi. Un oggetto pu&ograve;
+essere costituito da un altro contenitore o da un oggetto grafico. Infatti, molti
+oggetti grafici sono a loro volta dei contenitori, compreso il bottone, anche se
+tipicamente all'interno del bottone mettiamo solo una etichetta.
+<p>
+
+Usando queste chiamate, GTK riesce a capire dove si vogliono piazzare i propri
+widget, in modo di essere poi in grado di effettuare il ridimensionamento
+automatico e altre cose interessanti. Esiste poi un insieme di opzioni che riguardano
+il modo in cui i propri oggetti grafici dovrebbero essere impacchettati. Come
+si pu&ograve; immaginare, questo metodo d&agrave; una buona flessibilit&agrave; nella creazione e
+nella disposizione dei propri widget.
+<sect1>Dettagli sulle Scatole
+<p>
+A causa di questa flessibilit&agrave;, le scatole per impacchettamento del GTK
+possono, di primo acchito, creare un po' di disorientamento. Sono infatti disponibili
+molte opzioni, e non &egrave; immediato il modo in cui si combinano l'una con l'altra.
+Alla fine per&ograve;, si possono ottenere essenzialmente cinque diversi stili.
+
+<p>
+<?
+<IMG ALIGN="center" SRC="packbox1.gif"
+VSPACE="15" HSPACE="10" ALT="Box Packing Example Image" WIDTH="528"
+HEIGHT="235">
+>
+
+
+Ogni linea contiene una scatola orizzontale (hbox) con diversi bottoni.
+La chiamata a gtk_box_pack &egrave; una scorciatoia per la chiamata di impacchettamento
+di ognuno dei bottoni nella hbox. Ognuno dei bottoni viene impacchettato nella
+hbox nello stesso modo (cio&egrave;, con gli stessi argomenti per la funzione gtk_box_pack_start ()).
+<p>
+Questa &egrave; la dichiarazione della funzione gtk_box_pack_start.
+
+<tscreen><verb>
+void gtk_box_pack_start (GtkBox *box,
+ GtkWidget *child,
+ gint expand,
+ gint fill,
+ gint padding);
+</verb></tscreen>
+Il primo argomento &egrave; la scatola nella quale si stanno inscatolando i
+widget, il secondo &egrave; il widget stesso. Gli oggetti per ora saranno
+bottoni, quindi quello che faremo sar&agrave; impacchettare bottoni in scatole.
+<p>
+L'argomento ``expand'' in gtk_box_pack_start() o gtk_box_pack_end() controlla
+se gli oggetti devono essere sistemati nella scatola in modo da riempire tutto
+lo spazio in diponibile presente nella scatola, in modo che la scatola si espanda fino
+ad occupare tutta l'area assegnatale (valore TRUE).
+La scatola pu&ograve; anche essere rimpiciolita in modo da contenere esattamente i
+widget (valore FALSE). Assegnare a expand il valore FALSE permette di giustificare
+a destra o sinistra i propri oggetti. In caso contrario, tutti gli ogetti si espandono
+fino ad adattarsi alla scatola, e il medesimo effetto si pu&ograve; ottenere usando solo una
+delle funzioni gtk_box_pack_start o pack_end.
+<p>
+L'argomento ``fill'' delle funzioni gtk_box_pack stabilisce se lo spazio disponibile
+nella scatola deve essere allocato agli oggetti (TRUE) o se deve essere mantenuto
+come riempimento attorno a questi oggetti (FALSE). Questo argomento ha effetto
+solo se a expand &egrave; assegnato il valore TRUE.
+<p>
+Quando si crea una nuova scatola, la funzione ha questo aspetto:
+
+<tscreen><verb>
+GtkWidget * gtk_hbox_new (gint homogeneous,
+ gint spacing);
+</verb></tscreen>
+
+L'argomento homogeneous di gtk_hbox_new (la stesso per gtk_vbox_new)
+determina se ogni oggetto nella scatola deve avere la stessa dimensione (cio&egrave;
+la stessa ampiezza in una hbox o la stessa altezza in una vbox). Se &egrave; settato,
+l'argomento expand delle routine gtk_box_pack &egrave; sempre attivato.
+<p>
+Qual &egrave; la differenza fra la spaziatura (che &egrave; stabilita quando la scatola
+viene creata) e il riempimento (che viene stabilito quando gli elementi vengono
+impacchettati)? La spaziatura viene inserita fra gli oggetti, mentre il
+riempimento viene aggiuno a ciascuno dei lati dell'oggetti. La seguente figura
+dovrebbe chiarire meglio questo punto:
+
+<?
+<IMG ALIGN="center" SRC="packbox2.gif"
+VSPACE="15" HSPACE="10" ALT="Box Packing Example Image" WIDTH="509"
+HEIGHT="213">
+>
+
+
+Di seguito &egrave; riportato il codice usato per creare le immagini precedenti.
+L'ho commentato in modo piuttosto pesante, in modo che non dovreste avere
+problemi nel seguirlo. Compilatelo voi stessi e preovate a giocarci un po'.
+
+<sect1>Programma Dimostrativo di Impacchettamento
+<p>
+
+<tscreen><verb>
+#include "gtk/gtk.h"
+
+void
+delete_event (GtkWidget *widget, gpointer *data)
+{
+ gtk_main_quit ();
+}
+
+/* Costruisco una nuova hbox riempita con bottoni-etichette. Gli
+ * argomenti per le varabili che ci interessano sono passati
+ * in questa funzione. Non mostriamo la scatola, ma mostriamo
+ * tutto quello che c'&egrave; dentro. */
+GtkWidget *make_box (gint homogeneous, gint spacing,
+ gint expand, gint fill, gint padding)
+{
+ GtkWidget *box;
+ GtkWidget *button;
+ char padstr[80];
+
+ /* costruisco una nuova hbox con i valori appropriati di
+ * homogeneous e spacing */
+ box = gtk_hbox_new (homogeneous, spacing);
+
+ /* costruisco una serie di bottoni con i valori appropriati */
+ button = gtk_button_new_with_label ("gtk_box_pack");
+ gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
+ gtk_widget_show (button);
+
+ button = gtk_button_new_with_label ("(box,");
+ gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
+ gtk_widget_show (button);
+
+ button = gtk_button_new_with_label ("button,");
+ gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
+ gtk_widget_show (button);
+
+ /* costruisco un bottone con l'etichetta che dipende dal valore di
+ * expand. */
+ if (expand == TRUE)
+ button = gtk_button_new_with_label ("TRUE,");
+ else
+ button = gtk_button_new_with_label ("FALSE,");
+
+ gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
+ gtk_widget_show (button);
+
+ /* Questo &egrave; la stessa cosa della creazione del bottone per "expand"
+ * pi&ugrave; sopra, ma usa la forma breve. */
+ button = gtk_button_new_with_label (fill ? "TRUE," : "FALSE,");
+ gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
+ gtk_widget_show (button);
+
+ sprintf (padstr, "%d);", padding);
+
+ button = gtk_button_new_with_label (padstr);
+ gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
+ gtk_widget_show (button);
+
+ return box;
+}
+
+int
+main (int argc, char *argv[])
+{
+ GtkWidget *window;
+ GtkWidget *button;
+ GtkWidget *box1;
+ GtkWidget *box2;
+ GtkWidget *separator;
+ GtkWidget *label;
+ GtkWidget *quitbox;
+ int which;
+
+ /* La nostra inizializzazione, non dimenticatela! :) */
+ gtk_init (&amp;argc, &amp;argv);
+
+ if (argc != 2) {
+ fprintf (stderr, "uso: packbox num, dove num &egrave; 1, 2, o 3.\n");
+ /* questo fa solo un po' di pulizia in GTK, ed esce con un valore 1. */
+ gtk_exit (1);
+ }
+
+ which = atoi (argv[1]);
+
+ /* Creiamo la nostra finestra */
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+
+ /* Ci si dovrebbe sempre ricordare di connettere il segnale di destroy
+ * alla finestra principale. Ci&ograve; &egrave; molto importante per avere un funzionamento
+ * corretto dal punto di vista intuitivo */
+ gtk_signal_connect (GTK_OBJECT (window), "delete_event",
+ GTK_SIGNAL_FUNC (delete_event), NULL);
+ gtk_container_border_width (GTK_CONTAINER (window), 10);
+
+ /* Creiamo una scatola verticale (vbox) in cui impacchettare quelle
+ * orizzontali. Questo ci permette di impilare le scatole orizzontali
+ * piene di bottoni una sull'altra in questa vbox. */
+
+ box1 = gtk_vbox_new (FALSE, 0);
+
+ /* Decide quale esempio si deve mostrare. Corrispondono alle figure precedenti */
+ switch (which) {
+ case 1:
+ /* creare una nuova etichetta. */
+ label = gtk_label_new ("gtk_hbox_new (FALSE, 0);");
+
+ /* allineare l'etichetta al lato sinistro. Discuteremo questa e altre
+ * funzioni nella sezione dedicata agli attributi degli oggetti grafici. */
+ gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
+
+ /* Impacchettare l'etichetta nella scatola verticale (vbox box1).
+ * Ricordare che gli oggetti che vengono aggiunti in una vbox vengono
+ * impacchettati uno sopra all'altro in ordine. */
+ gtk_box_pack_start (GTK_BOX (box1), label, FALSE, FALSE, 0);
+
+ /* mostrare l'etichetta */
+ gtk_widget_show (label);
+
+ /* chiamare la nostra funzione make_box - homogeneous = FALSE,
+ * spacing = 0, expand = FALSE, fill = FALSE, padding = 0 */
+ box2 = make_box (FALSE, 0, FALSE, FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
+ gtk_widget_show (box2);
+
+ /* chiamare la nostra funzione make_box - homogeneous = FALSE, spacing = 0,
+ * expand = FALSE, fill = FALSE, padding = 0 */
+ box2 = make_box (FALSE, 0, TRUE, FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
+ gtk_widget_show (box2);
+
+ /* Gli argomenti sono: homogeneous, spacing, expand, fill, padding */
+ box2 = make_box (FALSE, 0, TRUE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
+ gtk_widget_show (box2);
+
+ /* Questo crea un separatore. Li conosceremo meglio in seguito,
+ * comunque sono piuttosto semplici. */
+ separator = gtk_hseparator_new ();
+
+ /* Impacchetta il separatore nella vbox. Ricordare che stiamo impacchettando
+ * ognuno di questi oggetti in una vbox, cosicch&eacute; essi verranno
+ * impacchettati verticalmente. */
+ gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5);
+ gtk_widget_show (separator);
+
+ /* crea un'altra nuova etichetta e mostrala. */
+ label = gtk_label_new ("gtk_hbox_new (TRUE, 0);");
+ gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
+ gtk_box_pack_start (GTK_BOX (box1), label, FALSE, FALSE, 0);
+ gtk_widget_show (label);
+
+ /* Gli argomenti sono: homogeneous, spacing, expand, fill, padding */
+ box2 = make_box (TRUE, 0, TRUE, FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
+ gtk_widget_show (box2);
+
+ /* Gli argomenti sono: homogeneous, spacing, expand, fill, padding */
+ box2 = make_box (TRUE, 0, TRUE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
+ gtk_widget_show (box2);
+
+ /* ancora un nuovo separatore. */
+ separator = gtk_hseparator_new ();
+ /* Gli ultimi 3 argumenti per gtk_box_pack_start sono: expand, fill, padding. */
+ gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5);
+ gtk_widget_show (separator);
+
+ break;
+
+ case 2:
+
+ /* creare una nuova etichetta, ricordare che box1 &egrave; la vbox creata
+ * vicino all'inizio di main() */
+ label = gtk_label_new ("gtk_hbox_new (FALSE, 10);");
+ gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
+ gtk_box_pack_start (GTK_BOX (box1), label, FALSE, FALSE, 0);
+ gtk_widget_show (label);
+
+ /* Gli argomenti sono: homogeneous, spacing, expand, fill, padding */
+ box2 = make_box (FALSE, 10, TRUE, FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
+ gtk_widget_show (box2);
+
+ /* Gli argomenti sono: homogeneous, spacing, expand, fill, padding */
+ box2 = make_box (FALSE, 10, TRUE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
+ gtk_widget_show (box2);
+
+ separator = gtk_hseparator_new ();
+ /* Gli ultimi tre arcomenti di gtk_box_pack_start sono: expand, fill, padding. */
+ gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5);
+ gtk_widget_show (separator);
+
+ label = gtk_label_new ("gtk_hbox_new (FALSE, 0);");
+ gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
+ gtk_box_pack_start (GTK_BOX (box1), label, FALSE, FALSE, 0);
+ gtk_widget_show (label);
+
+ /* Gli argomenti sono: homogeneous, spacing, expand, fill, padding */
+ box2 = make_box (FALSE, 0, TRUE, FALSE, 10);
+ gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
+ gtk_widget_show (box2);
+
+ /* Gli argomenti sono: homogeneous, spacing, expand, fill, padding */
+ box2 = make_box (FALSE, 0, TRUE, TRUE, 10);
+ gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
+ gtk_widget_show (box2);
+
+ separator = gtk_hseparator_new ();
+ /* Gli ultimi tre argomenti di gtk_box_pack_start sono: expand, fill, padding. */
+ gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5);
+ gtk_widget_show (separator);
+ break;
+
+ case 3:
+
+ /* Questo dimostra la possibilit&agrave; di usare use gtk_box_pack_end() per
+ * giustificare gli oggetti a destra. Per prima cosa creiamo una
+
+ * nuova scatola come prima. */
+ box2 = make_box (FALSE, 0, FALSE, FALSE, 0);
+ /* creiamo l'etichetta che sar&agrave; aggiunta alla fine. */
+ label = gtk_label_new ("end");
+ /* impacchettiamola usando gtk_box_pack_end(), cos&igrave; che viene inserita
+ * sul lato destro della hbox creata nella chiamata a the make_box(). */
+ gtk_box_pack_end (GTK_BOX (box2), label, FALSE, FALSE, 0);
+ /* mostriamo l'etichetta. */
+ gtk_widget_show (label);
+
+ /* impacchettiamo box2 in box1 (the vbox, ricordate? :) */
+ gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
+ gtk_widget_show (box2);
+
+ /* un separatore per il fondo */
+ separator = gtk_hseparator_new ();
+ /* Questo assegna esplicitamente al separatore l'ampiezza di 400 pixel
+ * e l'altezza di 5 pixel. Ci&ograve; fa s&igrave; che la hbox che abbiamo creato sia
+ * anche essa larga 400 pixel, e che l'etichetta finale sia separata dalle
+ * altre etichette nella hbox. In caso contrario, tutti gli oggetti nella
+ * hbox sarebbero impacchettati il pi&ugrave; vicino possibile. */
+ gtk_widget_set_usize (separator, 400, 5);
+ /* impacchetta il separatore nella vbox (box1) creata vicino all'inizio
+ * di main() */
+ gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5);
+ gtk_widget_show (separator);
+ }
+
+ /* Creare un'altra nuova hbox.. ricordate che ne possiamo usare quante ne vogliamo! */
+ quitbox = gtk_hbox_new (FALSE, 0);
+
+ /* Il nostro bottone di uscita. */
+ button = gtk_button_new_with_label ("Quit");
+
+
+ /* Configuriamo il segnale per distruggere la finestra. Ricordate che
+ * ci&ograve; mander&agrave; alla finestra il segnale "destroy", che verr&agrave; catturato
+ * dal nostro gestore di segnali che abbiamo definito in precedenza. */
+ gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
+ GTK_SIGNAL_FUNC (gtk_widget_destroy),
+ GTK_OBJECT (window));
+ /* impacchetta il bottone in quitbox.
+ * Gli ultimi tre argomenti di gtk_box_pack_start sono: expand, fill, padding. */
+ gtk_box_pack_start (GTK_BOX (quitbox), button, TRUE, FALSE, 0);
+ /* impacchetta quitbox nella vbox (box1) */
+ gtk_box_pack_start (GTK_BOX (box1), quitbox, FALSE, FALSE, 0);
+
+ /* impacchetta la vbox (box1), che ora contiene tutti i nostri oggetti,
+ * nella finestra principale. */
+ gtk_container_add (GTK_CONTAINER (window), box1);
+
+ /* e mostra tutto quel che rimane */
+ gtk_widget_show (button);
+ gtk_widget_show (quitbox);
+
+ gtk_widget_show (box1);
+ /* Mostriamo la finestra alla fine in modo che tutto spunti fuori assieme. */
+ gtk_widget_show (window);
+
+ /* E, naturalmente, la nostra funzione main. */
+ gtk_main ();
+
+ /* Il controllo ritorna a questo punto quando viene chiamata gtk_main_quit(),
+ * ma non quando si usa gtk_exit. */
+
+ return 0;
+}
+</verb></tscreen>
+
+<p>
+<sect1>Impacchettamento con uso di Tabelle
+<p>
+Diamo ora un'occhiata ad un altro modo di impacchettare - le Tabelle.
+In certe situazioni, possono risultare estremamente utili.
+
+Usando le tabelle, creiamo una griglia in cui possiamo piazzare gli oggetti.
+Gli oggetti possono occupare tanti spazi quanti ne specifichiamo.
+
+Naturalmente, la prima cosa da vedere &egrave; la funzione gtk_table_new:
+
+<tscreen><verb>
+GtkWidget* gtk_table_new (gint rows,
+ gint columns,
+ gint homogeneous);
+</verb></tscreen>
+<p>
+Il primo argomento rappresenta il numero di righe da mettere nella tabella,
+mentre il secondo &egrave; ovviamente il numero di colonne.
+
+L'argomento homogeneous ha a che fare con il modo in cui le caselle della tabella
+sono dimensionate. Se homogeneous ha il valore TRUE, le caselle sono ridimensionate
+fino alla dimensione del pi&ugrave; grande oggetto contenuto nella tabelle. Se &egrave; FALSE, la
+dimensione delle caselle&egrave; decisa dal pi&ugrave; alto oggetto in una certa riga e dal pi&ugrave;
+largo oggetto in una stessa colonna.
+
+Le righe e le colonne sono disposte a partire da 0 fino a n, dove n &egrave; il numero
+che era stato specificato nella chiamata a gtk_table_new. Cos&igrave;, se specificate
+rows = 2 e columns = 2, lo schema avr&agrave; questo aspetto:
+
+<tscreen><verb>
+ 0 1 2
+0+----------+----------+
+ | | |
+1+----------+----------+
+ | | |
+2+----------+----------+
+</verb></tscreen>
+<p>
+Notate che il sistema di coordinate ha origine nel vertice in alto a sinistra. Per
+mettere un oggetto in una tabella, usate la seguente funzione:
+
+<tscreen><verb>
+void gtk_table_attach (GtkTable *table,
+ GtkWidget *child,
+ gint left_attach,
+ gint right_attach,
+ gint top_attach,
+ gint bottom_attach,
+ gint xoptions,
+ gint yoptions,
+ gint xpadding,
+ gint ypadding);
+</verb></tscreen>
+<p>
+In cui il primo argomento (``table'') &egrave; la tabella che avete creato e il secondo
+(``child'') &egrave; l'oggetto che volete piazzare nella tabella.
+
+Gli argomenti ``attach'' (right, left, top, bottom) specificano dove mettere l'oggetto
+e quante caselle adoperare. Se volete mettere un bottone nella casella in basso a destra
+nella nostra tabella 2x2, e volete che esso riempia SOLO quella casella, dovete porre
+left_attach = 1, right_attach = 2, top_attach = 1, bottom_attach = 2.
+
+Se invece volete che un oggetto si prenda tutta la riga pi&ugrave; in alto nella nostra tabella
+2x2, dovreste usare left_attach = 0, right_attach =2, top_attach = 0,
+bottom_attach = 1.
+
+Gli argomenti ``xoptions'' e ``yoptions'' sono usati per specificare le opzioni di impacchettamento;
+di essi si pu&ograve; fare l'OR in modo di ottenere opzioni multiple.
+
+Le opzioni sono:
+<itemize>
+<item>GTK_FILL - Se la parte di tabella in cui si vuole inserire il widget &egrave; pi&ugrave;
+grande dell'oggetto, e se si specifica GTK_FILL, l'oggetto viene espanso fino ad
+occupare tutto lo spazio disponibile.
+
+<item>GTK_SHRINK - Se si alloca all'oggetto nella tabella meno spazio del necessario
+(di solito succede quando l'utente ridimensiona la finestra), allora normalmente
+l'oggetto verrebbe spinto fuori dal fondo della finestra fino a sparire.
+Se invece si specifica GTK_SHRINK is specified, gli oggetti si rimpiccioliscono
+assieme alla tabella.
+
+<item>GTK_EXPAND - Questo fa s&igrave; che la tabella si espanda fino ad occupare tutto lo
+spazio che rimane nella finestra.
+</itemize>
+
+Il riempimento funziona come nelle scatole, con la creazione di un'area vuota
+attorno all'oggetto la cui dimensione viene specificata in pixel.
+
+La funzione gtk_table_attach() ha UN MUCCHIO di opzioni. Quindi, ecco una scorciatoia:
+
+<tscreen><verb>
+void gtk_table_attach_defaults (GtkTable *table,
+ GtkWidget *widget,
+ gint left_attach,
+ gint right_attach,
+ gint top_attach,
+ gint bottom_attach);
+</verb></tscreen>
+
+Le xoptions e yoptions vengono posti per difetto a GTK_FILL | GTK_EXPAND, e sia xpadding
+che ypadding vengono posti a 0. Il resto degli argomenti sono identici a quelli della funzione
+precedente.
+
+Ci sono poi le funzioni gtk_table_set_row_spacing() and gtk_table_set_col_spacing().
+Queste mettono dello spazio fra le righe (o colonne)in corrispondenza di una specifica
+riga (o colonna).
+
+<tscreen><verb>
+void gtk_table_set_row_spacing (GtkTable *table,
+ gint row,
+ gint spacing);
+</verb></tscreen>
+e
+<tscreen><verb>
+void gtk_table_set_col_spacing (GtkTable *table,
+ gint column,
+ gint spacing);
+</verb></tscreen>
+
+Notate che per le colonne lo spazio viene posto alla destra della colonna, mentre
+per le righe lo spazio viene posto al di sotto della riga.
+
+Si pu&ograve; poi inserire una spaziatura identica fra tutte le righe e/o colonne usando:
+
+<tscreen><verb>
+void gtk_table_set_row_spacings (GtkTable *table,
+ gint spacing);
+</verb></tscreen>
+<p>
+e
+<tscreen><verb>
+void gtk_table_set_col_spacings (GtkTable *table,
+ gint spacing);
+</verb></tscreen>
+<p>
+Notate che con queste chiamate, all'ultima riga e all'ultima colonna
+non viene assegnata alcuna spaziatura.
+
+<sect1>Esempio di Impacchettamento con Tabelle
+<p>
+Per il momento, si prega di fare riferimento all'esempio di tabella in
+testgtk.c distribuito con i sorgenti di gtk.
+
+
+<sect>Panoramica sui Widget
+<p>
+<p>
+La procedura generale di creazione di un widget in GTK prevede i seguenti passi:
+<enum>
+<item> gtk_*_new - una delle varie funzioni che servono per greare un nuovo widget.
+In questa sezione le vedremo tutte in dettaglio.
+
+<item> Connettere tutti i segnali che si vogliono usare alle funzione gestione appropriate.
+
+<item> Assegnare gli attributi all'oggetto.
+
+<item> Impacchettare l'oggetto in un contenitore usando la chiamate appropriata,
+per esempio gtk_container_add() o gtk_box_pack_start().
+
+<item> Mostrare l'oggetto con gtk_widget_show().
+</enum>
+<p>
+gtk_widget_show() fa s&igrave; che GTK sappia che abbiamo terminato di assegnare gli
+attributi dell'oggetto grafico, e che &egrave; pronto per essere visualizzato.
+Si pu&ograve; anche usare la funzione gtk_widget_hide per farlo sparire di nuovo.
+L'ordine in cui mostrate gli oggetti grafici non &egrave; importante, ma io suggerisco
+di mostrare per ultima la finestra, in modo che questa spunti fuori gi&agrave; completa,
+invece di vedere i singoli oggetti che arrivano sullo schermo a mano a mano che si
+formano. I figli di un oggetto grafico (anche una finestra &egrave; un oggetto grafico) non
+vengono infatti mostrati finch&eacute; la finestra stessa non viene mostrata usando la
+funzione gtk_widget_show().
+
+
+<sect1> Casting
+<p>
+Noterete andando avanti che GTK usa un sistema di casting di tipo. Questa operazione
+viene sempre effettuata usando delle macro che allo stesso tempo controllano la
+possibilit&agrave; di effettuare il cast sull'elemento dato e lo effettuano realmente.
+Alcune macro che avrete modo di incontrare sono:
+
+<itemize>
+<item> GTK_WIDGET(widget)
+<item> GTK_OBJECT(object)
+<item> GTK_SIGNAL_FUNC(function)
+<item> GTK_CONTAINER(container)
+<item> GTK_WINDOW(window)
+<item> GTK_BOX(box)
+</itemize>
+
+Tutte queste funzioni sono usate per fare il cast di argomenti di funzione. Le vedrete
+negli esempi, e capirete se &egrave; il caso di usarle semplicemente guardando alle
+dichiarazioni delle funzioni.
+
+Come potrete vedere pi&ugrave; sotto nella gerarchia delle classi, tutti i GtkWidgets
+sono derivati dalla classe base GtkObject. Ci&ograve; significa che potete usare un
+widget in ogni posto in cui una funzione richiede un oggetto - semplicemente
+usate la macro GTK_OBJECT().
+
+Per esempio:
+
+<tscreen><verb>
+gtk_signal_connect(GTK_OBJECT(button), "clicked",
+ GTK_SIGNAL_FUNC(callback_function), callback_data);
+</verb></tscreen>
+
+Questo fa il cast del bottone in un oggetto e fornisce alla chiamata di ritorno
+un cast al puntatore a funzione.
+
+Molti oggetti grafici sono anche contenitori. Se guardate alla gerarchia delle
+classi pi&ugrave; sotto, vedrete che molti oggetti grafici sono derivati dalla classe
+GtkContainer. Ognuna di queste classi pu&ograve; essere usata, con la macro GTK_CONTAINER,
+come argomento per funzioni che richiedono un contenitore.
+
+Sfortunatamente, in questo tutorial non si parler&agrave; in modo estensivo di queste macro,
+ma raccomando di dare un'occhiata ai file header di GTK. Pu&ograve; essere una cosa molto
+educativa. Infatti, non &egrave; difficile imparare come funziona un oggetto solo guardando
+le dichiarazioni delle funzioni.
+
+<p>
+<sect1>Gerarchia degli Oggetti Grafici
+<p>
+Ecco, per vostro riferimento, la gerarchia delle classi usata per implementare gli
+oggetti grafici.
+
+<tscreen><verb>
+ GtkObject
+ +-- GtkData
+ | \-- GtkAdjustment
+ |
+ \-- GtkWidget
+ +-- GtkContainer
+ | +-- GtkBin
+ | | +-- GtkAlignment
+ | | +-- GtkFrame
+ | | | *-- GtkAspectFrame
+ | | |
+ | | +-- GtkItem
+ | | | +-- GtkListItem
+ | | | +-- GtkMenuItem
+ | | | | +-- GtkCheckMenuItem
+ | | | | *-- GtkRadioMenuItem
+ | | | |
+ | | | *-- GtkTreeItem
+ | | |
+ | | +-- GtkViewport
+ | | \-- GtkWindow
+ | | +-- GtkDialog
+ | | \-- GtkFileSelection
+ | |
+ | +-- GtkBox
+ | | +-- GtkHBox
+ | | \-- GtkVBox
+ | | +-- GtkColorSelection
+ | | \-- GtkCurve
+ | |
+ | +-- GtkButton
+ | | +-- GtkOptionMenu
+ | | \-- GtkToggleButton
+ | | \-- GtkCheckButton
+ | | \-- GtkRadioButton
+ | |
+ | +-- GtkList
+ | +-- GtkMenuShell
+ | | +-- GtkMenu
+ | | \-- GtkMenuBar
+ | |
+ | +-- GtkNotebook
+ | +-- GtkScrolledWindow
+ | +-- GtkTable
+ | \-- GtkTree
+ |
+ +-- GtkDrawingArea
+ +-- GtkEntry
+ +-- GtkMisc
+ | +-- GtkArrow
+ | +-- GtkImage
+ | +-- GtkLabel
+ | \-- GtkPixmap
+ |
+ +-- GtkPreview
+ +-- GtkProgressBar
+ +-- GtkRange
+ | +-- GtkScale
+ | | +-- GtkHScale
+ | | \-- GtkVScale
+ | |
+ | \-- GtkScrollbar
+ | +-- GtkHScrollbar
+ | \-- GtkVScrollbar
+ |
+ +-- GtkRuler
+ | +-- GtkHRuler
+ | \-- GtkVRuler
+ |
+ \-- GtkSeparator
+ +-- GtkHSeparator
+ \-- GtkVSeparator
+
+</verb></tscreen>
+<p>
+
+<sect1>Oggetti senza Finestre
+<p>
+Gli oggetti seguenti non hanno una finestra associata. Se volete catturare
+degli eventi, dovrete usare l'oggetto GtkEventBox. Vedete anche la sezione su
+<ref id="sec_The_EventBox_Widget" name="Il Widget EventBox">
+
+<tscreen><verb>
+GtkAlignment
+GtkArrow
+GtkBin
+GtkBox
+GtkImage
+GtkItem
+GtkLabel
+GtkPaned
+GtkPixmap
+GtkScrolledWindow
+GtkSeparator
+GtkTable
+GtkViewport
+GtkAspectFrame
+GtkFrame
+GtkVPaned
+GtkHPaned
+GtkVBox
+GtkHBox
+GtkVSeparator
+GtkHSeparator
+</verb></tscreen>
+<p>
+Proseguiremo la nostra esplorazione di GTK esaminando uno alla volta tutti
+gli oggetti, creando qualche semplice funzione per mostrarli. Un'altra
+buona sorgente &egrave; il programma testgtk.c che viene fornito con GTK. Potete
+trovarlo in gtk/testgtk.c.
+
+<sect>Il Widget Bottone (Button)
+<p>
+<sect1>Bottoni Normali
+<p>
+Ormai abbiamo visto tutto quello che c'&egrave; da vedere riguardo all'oggetto
+``bottone''. E' piuttosto semplice, ma ci sono due modi per crare un bottone.
+Potete usare gtk_button_new_with_label() per creare un bottone con una
+etichetta, o usare gtk_button_new() per creare un bottone vuoto. In tal caso &egrave; poi
+vostro compito impacchettare un'etichetta o una pixmap sul bottone creato.
+Per fare ci&ograve;, create una nuova scatola, e poi impacchettateci i vostri
+oggetti usando la solita gtk_box_pack_start, e infine usate la funzione
+gtk_container_add per impacchettare la scatola nel bottone.
+<p>
+Ecco un esempio di utilizzo di gtk_button_new per creare un bottone con
+un'immagine ed un'etichetta su di s&egrave;. Ho separato il codice usato per
+creare la scatola in modo che lo possiate usare nei vostri programmi.
+
+<tscreen><verb>
+#include <gtk/gtk.h>
+
+
+/* crea una nuova hbox contenente un'immagine ed un'etichetta
+ * e ritorna la scatola creata. */
+
+GtkWidget *xpm_label_box (GtkWidget *parent, gchar *xpm_filename, gchar *label_text)
+{
+ GtkWidget *box1;
+ GtkWidget *label;
+ GtkWidget *pixmapwid;
+ GdkPixmap *pixmap;
+ GdkBitmap *mask;
+ GtkStyle *style;
+
+ /* creare una scatola per una xpm ed una etichetta */
+ box1 = gtk_hbox_new (FALSE, 0);
+ gtk_container_border_width (GTK_CONTAINER (box1), 2);
+
+ /* ottengo lo stile del bottone. Penso che sia per avere il colore
+ * dello sfondo. Se qualcuno sa il vero motivo, &egrave; pregato di dirmelo. */
+ style = gtk_widget_get_style(parent);
+
+ /* e ora via con le faccende dell'xpm stuff. Carichiamo l'xpm*/
+ pixmap = gdk_pixmap_create_from_xpm (parent->window, &amp;mask,
+ &amp;style->bg[GTK_STATE_NORMAL],
+ xpm_filename);
+ pixmapwid = gtk_pixmap_new (pixmap, mask);
+
+ /* creiamo l'etichetta per il bottone */
+ label = gtk_label_new (label_text);
+
+ /* impacchettiamo la pixmap e l'etichetta nella scatola */
+ gtk_box_pack_start (GTK_BOX (box1),
+ pixmapwid, FALSE, FALSE, 3);
+
+ gtk_box_pack_start (GTK_BOX (box1), label, FALSE, FALSE, 3);
+
+ gtk_widget_show(pixmapwid);
+ gtk_widget_show(label);
+
+ return (box1);
+}
+
+/* la nostra solita funzione di callback */
+void callback (GtkWidget *widget, gpointer *data)
+{
+ g_print ("Hello again - %s was pressed\n", (char *) data);
+}
+
+
+int main (int argc, char *argv[])
+{
+ /* GtkWidget &egrave; il tipo per contenere gli oggetti */
+ GtkWidget *window;
+ GtkWidget *button;
+ GtkWidget *box1;
+
+ gtk_init (&amp;argc, &amp;argv);
+
+ /* creiamo una nuova finestra */
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+
+ gtk_window_set_title (GTK_WINDOW (window), "Pixmap'd Buttons!");
+
+ /* E' una buona idea fare questo per tutte le finestre. */
+ gtk_signal_connect (GTK_OBJECT (window), "destroy",
+ GTK_SIGNAL_FUNC (gtk_exit), NULL);
+
+
+ /* assegnamo lo spessore del bordo della finestra */
+ gtk_container_border_width (GTK_CONTAINER (window), 10);
+
+ /* creiamo un nuovo bottone */
+ button = gtk_button_new ();
+
+ /* Ormai dovreste esservi abituati a vedere la maggior parte di
+ * queste funzioni */
+ gtk_signal_connect (GTK_OBJECT (button), "clicked",
+ GTK_SIGNAL_FUNC (callback), (gpointer) "cool button");
+
+ /* questa chiama la nostra funzione di creazione di scatole */
+ box1 = xpm_label_box(window, "info.xpm", "cool button");
+
+ /* impacchetta e mostra tutti i nostri oggetti */
+ gtk_widget_show(box1);
+
+ gtk_container_add (GTK_CONTAINER (button), box1);
+
+ gtk_widget_show(button);
+
+ gtk_container_add (GTK_CONTAINER (window), button);
+
+ gtk_widget_show (window);
+
+ /* mettiti in gtk_main e aspetta che cominci il divertimento! */
+ gtk_main ();
+
+ return 0;
+}
+</verb></tscreen>
+La funzione xpm_label_box pu&ograve; essere usata per impacchettare delle xpm
+e delle etichette su qualsiasi oggetto che pu&ograve; essere un contenitore.
+
+<sect1> Bottoni a Commutazione (Toggle Buttons)
+<p>
+I bottoni a commutazione sono molto simili ai bottoni normali, tranne che per il
+fatto che essi si trovano sempre in uno di due stati, che si alternano ad ogni
+click. Possono trovarsi nello stato ``premuto'', e quando li si ripreme, tornano
+ad essere sollevati. Ri-clickandoli, torneranno gi&ugrave;.
+
+I bottoni a commutazione sono la base per i bottoni di controllo (check button) e
+per i radio-bottoni, e quindi molte delle chiamate disponibili per i bottoni
+a commutazione vengono ereditati dai radio-bottoni e dai bottoni di controllo.
+Ma vedremo questi aspetti nel momento in cui li incontreremo.
+
+Creare un nuovo bottone a commutazione:
+
+<tscreen><verb>
+GtkWidget* gtk_toggle_button_new (void);
+
+GtkWidget* gtk_toggle_button_new_with_label (gchar *label);
+</verb></tscreen>
+<p>
+Come potete immaginare, queste funzioni lavorano in modo identico che per
+i bottoni normali. La prima crea un bottone a commutazione vuoto e la seconda un
+bottone con un'etichetta.
+<p>
+Per ottenere lo stato dei widget a commutazione, compresi i radio-bottoni e i
+bottoni di controllo, si pu&ograve; usare una macro come mostrato nell'esempio
+pi&ugrave; sotto. In questo modo lo stato dell'oggetto commutabile viene valutato in
+una funzione di ritorno. Il segnale emesso dai bottoni a commutazione
+(toggle button, il radio button o il check button) che ci interessa &egrave; il segnale
+``toggled''. Per controllare lo stato di questi bottoni, create un gestore di
+segnali che catturi il ``toggled'', e usate la macro per determinare
+il suo stato. La funzione di callback avr&agrave; un aspetto pi&ugrave; o meno cos&igrave;:
+
+<tscreen><verb>
+void toggle_button_callback (GtkWidget *widget, gpointer data)
+ {
+ if (GTK_TOGGLE_BUTTON (widget)->active)
+ {
+ /* Se il programma si &egrave; arrivato a questo punto, il bottone
+ * a commutazione &egrave; sollevato */
+
+ } else {
+
+ /* il bottone &egrave; abbassato */
+ }
+ }
+ </verb></tscreen>
+
+<!--
+
+COMMENTED!
+
+<tscreen><verb>
+guint gtk_toggle_button_get_type (void);
+</verb></tscreen>
+<p>
+No idea... they all have this, but I dunno what it is :)
+
+
+<tscreen><verb>
+void gtk_toggle_button_set_mode (GtkToggleButton *toggle_button,
+ gint draw_indicator);
+</verb></tscreen>
+<p>
+No idea.
+-->
+
+<tscreen><verb>
+void gtk_toggle_button_set_state (GtkToggleButton *toggle_button,
+ gint state);
+</verb></tscreen>
+<p>
+La chiamata qui sopra pu&ograve; essere usata per fare l'assegnazione dello stato
+del bottone a commutazione e dei suoi figli, il radio-bottone e il bottone di
+controllo. Passando come primo argomento a questa funzione il vostro bottone e
+come secondo argomento il valore TRUE o FALSE, si pu&ograve; specificare se il
+bottone deve essere sollevato (rilasciato) o abbassato (premuto). Il valore
+di difetto &egrave; sollevato, cio&egrave; FALSE.
+
+Notate che quando usate la funzione gtk_toggle_button_set_state(), e lo
+stato viene cambiato, si ha il risultato che il bottone emette il segnale
+``clicked''.
+
+<tscreen><verb>
+void gtk_toggle_button_toggled (GtkToggleButton *toggle_button);
+</verb></tscreen>
+<p>
+Questa funzione semplicemente commuta il bottone, ed emette il segnale ``toggled''.
+
+<sect1> Bottoni di Controllo (Check Buttons)
+<p>
+I bottoni di controllo ereditano molte propriet&agrave; e funzioni dal bottone a commutazione,
+ma hanno un aspetto un po' diverso. Invece di essere bottoni contenenti del testo,
+si tratta di quadratini con del testo alla propria destra. Questi bottoni sono
+spesso usati nelle applicazioni per commutare fra lo stato attivato e disattivato delle
+opzioni.
+
+Le due funzioni di creazione sono analoghe a quelle del bottone normale..
+
+<tscreen><verb>
+GtkWidget* gtk_check_button_new (void);
+
+GtkWidget* gtk_check_button_new_with_label (gchar *label);
+</verb></tscreen>
+
+La funzione new_with_label crea un bottone di controllo con una etichetta
+a fianco di esso.
+
+Per controllare lo stato del check button si opera in modo identico al bottone
+a commutazione.
+
+<sect1> Radio-Bottoni (Radio Buttons)
+<p>
+I radio-bottoni sono simili ai bottoni di controllo, tranne che per il
+fatto che sono sempre raggruppati in modo che solo uno alla volta di essi
+pu&ograve; essere selezionato (premuto). Tornano utili quando nella propria applicazione
+si ha bisogno di selezionare una opzione da una breve lista.
+
+La creazione di un nuovo radio-bottone si fa con una di queste chiamate:
+
+<tscreen><verb>
+GtkWidget* gtk_radio_button_new (GSList *group);
+
+GtkWidget* gtk_radio_button_new_with_label (GSList *group,
+ gchar *label);
+</verb></tscreen>
+<p>
+Avrete notato l'argomento in pi&ugrave; che c'&egrave; in queste chiamate. Queste hanno
+infatti bisogno dela specificazione di un ``gruppo'' per svolgere il loro compito.
+Per il primo bottone di un gruppo si deve passare come primo argomento il valore
+NULL. Dopodich&eacute; potete creare un gruppo usando la funzione:
+
+<tscreen><verb>
+GSList* gtk_radio_button_group (GtkRadioButton *radio_button);
+</verb></tscreen>
+
+<p>
+A questo punto potete passare questo gruppo ad ogni chiamata successiva a
+gtk_radio_button_new o new_with_label. E' anche una buona idea specificare
+esplicitamente quale dei bottoni dovr&agrave; essere quello premuto per difetto,
+usando:
+
+<tscreen><verb>
+void gtk_toggle_button_set_state (GtkToggleButton *toggle_button,
+ gint state);
+</verb></tscreen>
+<p>
+Questa funzione &egrave; descritta nella sezione sui bottoni a commutazione, e funziona
+nello stesso identico modo.
+
+<p>
+[Inserir&ograve; un esempio di come usare questi oggetti, penso che sarebbe molto
+utile]
+
+
+<sect> Alcuni Widget
+<p>
+<sect1> L'Etichetta (Label)
+<p>
+Le etichette sono molto usate in GTK, e sono relativamente semplici. Le
+etichette non emettono segnali, dal momento che non hanno una finestra
+X a loro assegnata. Se avete la necessit&agrave; di avere dei segnali o di fare
+delle operazioni di clipping, potete usare il widget EventBox.
+
+Per creare una nuova etichetta, si usa:
+
+<tscreen><verb>
+GtkWidget* gtk_label_new (char *str);
+</verb></tscreen>
+
+In cui l'unico argomento &egrave; la stringa che si vuole sia mostrata.
+
+Per cambiare il testo dell'etichetta dopo che &egrave; stata creata, si usa
+la funzione:
+
+<tscreen><verb>
+void gtk_label_set (GtkLabel *label,
+ char *str);
+</verb></tscreen>
+<p>
+in cui il primo argomento &egrave; l'etichetta creata in precedenza (di cui si
+fa il cast usando la macro GTK_LABEL()), mentre il secondo &egrave; la nuova
+stringa.
+
+Nel caso, lo spazio necessario per la nuova stringa verr&agrave; regolato automaticamente.
+
+Per ottenere la stringa corrente si usa:
+
+<tscreen><verb>
+void gtk_label_get (GtkLabel *label,
+ char **str);
+</verb></tscreen>
+
+in cui il primo argomento &egrave; l'etichetta che avete creato, e il secondo
+&egrave; il valore di ritorno per la stringa.
+
+
+<sect1>Il Widget Suggerimenti (Tooltips)
+<p>
+I suggerimenti sono piccole stringhe di testo che spuntano quando lasciate il
+puntatore su un bottone o un altro widget per qualche secondo. Sono piuttosto
+semplici da usare, per cui ne dar&ograve; la spiegazione senza corredarla di esempi.
+Se volede vedere un po' di codice, date un'occhiata al programma testgtk.c
+distribuito con GTK.
+<p>
+Con alcuni widget (per esempio con l'etichetta) i suggerimenti non funzionano.
+<p>
+La prima chiamata che si usa per creare un nuovo tooltip &egrave; la seguente.
+In una data funzione, &egrave; necessario chiamarla una sola volta: il GtkTooltip
+che viene ritornato da questa funzione pu&ograve; essere usato per creare suggerimenti
+multipli.
+
+<tscreen><verb>
+GtkTooltips *gtk_tooltips_new (void);
+</verb></tscreen>
+
+Una volta creato un nuovo suggerimento e il widget su cui lo volete usare,
+basta usare la seguente chiamata per fare l'assegnazione:
+
+<tscreen><verb>
+void gtk_tooltips_set_tips (GtkTooltips *tooltips,
+ GtkWidget *widget,
+ gchar *tips_text);
+</verb></tscreen>
+
+Il primo argomento &egrave; il suggerimento che era gi&agrave; stato creato, che &egrave; seguito
+dal widget da cui volete che spunti il suggerimento e dal testo che volete
+venga mostrato.
+<p>
+Ecco un piccolo esempio:
+
+<tscreen><verb>
+GtkTooltips *tooltips;
+GtkWidget *button;
+...
+tooltips = gtk_tooltips_new ();
+button = gtk_button_new_with_label ("button 1");
+...
+gtk_tooltips_set_tips (tooltips, button, "This is button 1");
+</verb></tscreen>
+
+Ci sono anche altre funzioni che si usano con i suggerimenti. Eccone una lista
+con una breve descrizione di quello che fanno.
+
+<tscreen><verb>
+void gtk_tooltips_destroy (GtkTooltips *tooltips);
+</verb></tscreen>
+
+Distrugge un suggerimento esistente.
+
+<tscreen><verb>
+void gtk_tooltips_enable (GtkTooltips *tooltips);
+</verb></tscreen>
+
+Abilita un gruppo di suggerimenti disbilitato.
+
+<tscreen><verb>
+void gtk_tooltips_disable (GtkTooltips *tooltips);
+</verb></tscreen>
+
+Disabilita un gruppo di suggerimenti abilitato.
+
+<tscreen><verb>
+void gtk_tooltips_set_delay (GtkTooltips *tooltips,
+ gint delay);
+
+</verb></tscreen>
+Stabilisce quanti millisecondi si deve mantenere il puntatore sopra al
+widget prima che venga mostrato il suggerimento. Il valore di difetto
+&egrave; di 1000 millisecondi.
+
+<tscreen><verb>
+void gtk_tooltips_set_tips (GtkTooltips *tooltips,
+ GtkWidget *widget,
+ gchar *tips_text);
+</verb></tscreen>
+
+Cambia il testo di un suggerimento gi&agrave; esistente.
+
+<tscreen><verb>
+void gtk_tooltips_set_colors (GtkTooltips *tooltips,
+ GdkColor *background,
+ GdkColor *foreground);
+</verb></tscreen>
+
+Assegna i colori di primo piano e di sfondo dei suggerimenti. (Non ho idea
+di come si specifichino i colori).
+<p>
+E questo &egrave; tutto riguardo alle funzioni relative ai suggerimenti. Pi&ugrave;
+di quanto avreste mai voluto sapere :)
+
+<sect1> La Barra di Avanzamento (Progress Bar)
+<p>
+Le barre di avanzamento sono usate per mostrare lo stato di una operazione. Come potete
+vedere nel frammento di codice qui sotto, sono piuttosto semplici da usare.
+Ma prima vediamo come cominciare con la chiamata per creare una nuova progrss
+bar.
+
+<tscreen><verb>
+GtkWidget *gtk_progress_bar_new (void);
+</verb></tscreen>
+
+Ora che la barra di avanzamento &egrave; stata creata, possiamo usarla..
+
+<tscreen><verb>
+void gtk_progress_bar_update (GtkProgressBar *pbar, gfloat percentage);
+</verb></tscreen>
+
+Il primo argomento &egrave; la barra di avanzamento su cui volete lavorare, e il secondo
+&egrave; la quantit&agrave; 'completato', cio&egrave; la quantit&agrave; di riempimento della progress
+bar fra 0 e 100% (un numero reale fra 0 e 1).
+
+Le barre di avanzamento sono usate di solito con funzioni di timeout o altre di
+questo tipo (vedi alla sezione <ref id="sec_timeouts" name="Timeouts,
+I/O and Idle Functions">) per dare l'illusione del multitasking. Tutte
+usano la funzione gtk_progress_bar_update nello stesso modo.
+
+Ecco un esempio di barra di avanzamento, in cui l'aggiornamento avviene usando
+dei timeout. Questo codice vi mostra anche come riinizializzare le
+barre di avanzamento.
+
+<tscreen><verb>
+#include <gtk/gtk.h>
+
+static int ptimer = 0;
+int pstat = TRUE;
+
+/* Questa funzione incrementa e aggiorna la barra di avanzamento, e la rimette
+ a zero se pstat &egrave; FALSE */
+gint progress (gpointer data)
+{
+ gfloat pvalue;
+
+ /* ottiene il valore corrente della status bar */
+ pvalue = GTK_PROGRESS_BAR (data)->percentage;
+
+ if ((pvalue >= 1.0) || (pstat == FALSE)) {
+ pvalue = 0.0;
+ pstat = TRUE;
+ }
+ pvalue += 0.01;
+
+ gtk_progress_bar_update (GTK_PROGRESS_BAR (data), pvalue);
+
+ return TRUE;
+}
+
+/* Questa funzione segnala la riinizializzazione della
+ barra di avanzamento */
+void progress_r (void)
+{
+ pstat = FALSE;
+}
+
+void destroy (GtkWidget *widget, gpointer *data)
+{
+ gtk_main_quit ();
+}
+
+int main (int argc, char *argv[])
+{
+ GtkWidget *window;
+ GtkWidget *button;
+ GtkWidget *label;
+ GtkWidget *table;
+ GtkWidget *pbar;
+
+ gtk_init (&amp;argc, &amp;argv);
+
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+
+ gtk_signal_connect (GTK_OBJECT (window), "delete_event",
+ GTK_SIGNAL_FUNC (destroy), NULL);
+
+ gtk_container_border_width (GTK_CONTAINER (window), 10);
+
+ table = gtk_table_new(3,2,TRUE);
+ gtk_container_add (GTK_CONTAINER (window), table);
+
+ label = gtk_label_new ("Progress Bar Example");
+ gtk_table_attach_defaults(GTK_TABLE(table), label, 0,2,0,1);
+ gtk_widget_show(label);
+ /* Crea una nuova barra di avanzamento, impacchettala nella tabella
+ e mostrala */
+ pbar = gtk_progress_bar_new ();
+ gtk_table_attach_defaults(GTK_TABLE(table), pbar, 0,2,1,2);
+ gtk_widget_show (pbar);
+
+ /* Attiva un timeout che gestisca l'aggiornamento automatico della barra */
+ ptimer = gtk_timeout_add (100, progress, pbar);
+
+ /* Questo bottone segnala alla barra che deve essere resettata */
+ button = gtk_button_new_with_label ("Reset");
+ gtk_signal_connect (GTK_OBJECT (button), "clicked",
+ GTK_SIGNAL_FUNC (progress_r), NULL);
+ gtk_table_attach_defaults(GTK_TABLE(table), button, 0,1,2,3);
+ gtk_widget_show(button);
+
+ button = gtk_button_new_with_label ("Cancel");
+ gtk_signal_connect (GTK_OBJECT (button), "clicked",
+ GTK_SIGNAL_FUNC (destroy), NULL);
+
+ gtk_table_attach_defaults(GTK_TABLE(table), button, 1,2,2,3);
+ gtk_widget_show (button);
+
+ gtk_widget_show(table);
+ gtk_widget_show(window);
+
+ gtk_main ();
+
+ return 0;
+}
+</verb></tscreen>
+
+In questo programmino ci sono quattro aree che riguardano il modo di
+uso generale delle Barre di Avanzamento; le vediamo ora nell'ordine.
+
+<tscreen><verb>
+pbar = gtk_progress_bar_new ();
+</verb></tscreen>
+
+Questo codice crea una nuova barra ciamata pbar.
+
+<tscreen><verb>
+ptimer = gtk_timeout_add (100, progress, pbar);
+</verb></tscreen>
+
+Questo codice usa dei timeout per abilitare degli intervalli di tempo uguali.
+Per usare le barre di avanzamento non &egrave; per&ograve; necessario servirsi di timeout.
+
+<tscreen><verb>
+pvalue = GTK_PROGRESS_BAR (data)->percentage;
+</verb></tscreen>
+
+Qui si assegna a pvalue il valore corrente della percentuale di avanzamento.
+
+<tscreen><verb>
+gtk_progress_bar_update (GTK_PROGRESS_BAR (data), pvalue);
+</verb></tscreen>
+
+Infine, questo codice aggiorna la barra di avanzamento con il valore di pvalue.
+
+Questo &egrave; tutto quanto c'&egrave; da sapere sulle barre di avanzamento, divertitevi.
+
+<sect1> Dialoghi
+<p>
+
+Il widget ``Dialogo'' &egrave; molto semplice: si tratta in realt&agrave; di una finestra
+con alcuni elementi pre-impacchettati. La struttura di un dialogo &egrave; la
+seguente:
+
+<tscreen><verb>
+struct GtkDialog
+{
+ GtkWindow window;
+
+ GtkWidget *vbox;
+ GtkWidget *action_area;
+};
+</verb></tscreen>
+
+Come potete vedere, crea semplicemente una finestra vi inserisce una vbox
+in cima, poi un separatore e infine una hbox come ``area di azione''.
+
+Un Dialogo pu&ograve; essere utilizzato per messaggi per l'utente e
+altri scopi simili. E' un widget molto essenziale, che ha una sola funzione,
+e precisamente:
+
+<tscreen><verb>
+GtkWidget* gtk_dialog_new (void);
+</verb></tscreen>
+
+Per cui, per creare una nuova finestra di dialogo, uate:
+
+<tscreen><verb>
+GtkWidget window;
+window = gtk_dialog_new ();
+</verb></tscreen>
+
+Questa funzione crea una finestra di dialogo, dopodich&eacute; sta a voi
+utilizzarla. Potete mettere un bottone nella action_area facendo
+qualcosa del tipo:
+
+<tscreen><verb>
+button = ...
+gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area), button,
+ TRUE, TRUE, 0);
+gtk_widget_show (button);
+</verb></tscreen>
+
+Potreste anche aggiungere, ad esempio, un'etichetta all'area della vbox,
+con qualcosa di questo genere:
+
+<tscreen><verb>
+label = gtk_label_new ("Dialogs are groovy");
+gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox), label, TRUE,
+ TRUE, 0);
+gtk_widget_show (label);
+</verb></tscreen>
+
+Per provare a usare una finestra di dialogo, potreste provare a mettere
+due bottoni nella action_area, per esempio un bottone ``Cancella'' ed un
+bottone ``OK'' e un'etichetta nella vbox che chieda qualcosa all'utente o
+segnali un errore. Poi potreste collegare un diverso segnale a ciascun
+bottone ed eseguire l'operazione che l'utente che viene scelta dall'utente.
+
+
+<sect1> Pixmaps
+<p>
+
+Le Pixmap sono strutture dati che contengono immagini. Queste immagini
+possono poi essere utilizzate in varie occasioni, per esempio come
+icone sul desktop X-Window o come cusori. Una bitmap &egrave; una pixmap a due
+colori.
+
+Per usare una pixmap in GTK, dobbiamo in primo luogo creare una struttura
+GdkPixmap utilizzando le routine disponibili nello strato GDK. Una Pixmap
+pu&ograve; essere creata a partire da dati presenti in memoria o letti da un file.
+Vedremo ora una ad una le chiamate utilizzate per creare una pixmap.
+
+<tscreen><verb>
+GdkPixmap *gdk_bitmap_create_from_data( GdkWindow *window,
+ gchar *data,
+ gint width,
+ gint height );
+</verb></tscreen>
+<p>
+Si usa questa routine per creare una pixmap ad un solo piano (2 colori) da
+dati disponibili in memoria. Ogni bit nei dati indica lo stato acceso o
+spento di un pixel. L'altezza (height) e la larghezza (width) sono espresse
+ in pixel. GdkWindow &egrave; un puntatore alla finestra corrente, dal momento che
+le risorse di una pixmap hanno significato solo nel contesto dello schermo
+in cui deve essere mostrata.
+
+<tscreen><verb>
+GdkPixmap* gdk_pixmap_create_from_data( GdkWindow *window,
+ gchar *data,
+ gint width,
+ gint height,
+ gint depth,
+ GdkColor *fg,
+ GdkColor *bg );
+</verb></tscreen>
+
+Questa &egrave; usata per creare una pixmap con la profondit&agrave; data (depth, ossia
+numero di colori) usando i dati specificati. fg e bg indicano i colori da
+usare per il primo piano e per lo sfondo.
+
+<tscreen><verb>
+GdkPixmap* gdk_pixmap_create_from_xpm( GdkWindow *window,
+ GdkBitmap **mask,
+ GdkColor *transparent_color,
+ const gchar *filename );
+</verb></tscreen>
+
+Il formato XPM &egrave; una rappresentazione di pixmap leggibile per X Window. E' una
+rappresentazione molto diffusa, e sono disponibili parecchi programmi per creare
+immagini in questo formato. Il file specificato da ``filename'' deve contenere
+un'immagine in questo formato, che viene caricato nella struttura pixmap.
+La maschera (mask) specifica quali pixel della pixmap devono essere opachi.
+Tutti gli altri pixel sono colorati usando il colore specificato da
+transparent_color. Pi&ugrave; sotto mostreremo un esempio di uso di questa funzione.
+
+<tscreen><verb>
+GdkPixmap* gdk_pixmap_create_from_xpm_d (GdkWindow *window,
+ GdkBitmap **mask,
+ GdkColor *transparent_color,
+ gchar **data);
+</verb></tscreen>
+
+Si possono incorporare piccole immagini all'interno di un programma sotto
+forma di dati in formato XPM. In questo modo, invece di leggerli da un file,
+si possono usare questi dati per creare una pixmap. Un esempio di questo tipo
+di dati &egrave;
+
+<tscreen><verb>
+/* XPM */
+static const char * xpm_data[] = {
+"16 16 3 1",
+" c None",
+". c #000000000000",
+"X c #FFFFFFFFFFFF",
+" ",
+" ...... ",
+" .XXX.X. ",
+" .XXX.XX. ",
+" .XXX.XXX. ",
+" .XXX..... ",
+" .XXXXXXX. ",
+" .XXXXXXX. ",
+" .XXXXXXX. ",
+" .XXXXXXX. ",
+" .XXXXXXX. ",
+" .XXXXXXX. ",
+" .XXXXXXX. ",
+" ......... ",
+" ",
+" "};
+</verb></tscreen>
+
+<tscreen><verb>
+void gdk_pixmap_destroy( GdkPixmap *pixmap );
+</verb></tscreen>
+<p>
+Quando abbiamo finito di usare una pixmap e pensiamo di non doverla riutilizzare
+presto, &egrave; una buona idea liberare queste risorse usando la funzione
+dk_pixmap_destroy. Le pixmap devono essere considerate una risorsa preziosa.
+
+Quando abbiamo creato una pixmap, possiamo mostrarla come un widget GTK.
+E' necessario creare un widget pixmap che contenga una pixmap GDK. Questa
+operazione viene compiuta usando
+
+<tscreen><verb>
+GtkWidget* gtk_pixmap_new( GdkPixmap *pixmap,
+ GdkBitmap *mask );
+</verb></tscreen>
+<p>
+Le altre chiamate per i widget pixmap sono
+
+<tscreen><verb>
+guint gtk_pixmap_get_type( void );
+void gtk_pixmap_set( GtkPixmap *pixmap,
+ GdkPixmap *val,
+ GdkBitmap *mask);
+void gtk_pixmap_get( GtkPixmap *pixmap,
+ GdkPixmap **val,
+ GdkBitmap **mask);
+</verb></tscreen>
+<p>
+La funzione gtk_pixmap_set viene usata per cambiare la pixmap che viene
+gestita correntemente dal widget.
+gtk_pixmap_set is used to change the pixmap that the widget is currently
+managing. ``val'' &egrave; la pixmap che &egrave; stata creata usando il GDK.
+Segue un esempio di uso di una pixmap in un bottone.
+
+<tscreen><verb>
+
+#include <gtk/gtk.h>
+
+
+/* dat XPM dell'icona Apri File */
+static const char * xpm_data[] = {
+"16 16 3 1",
+" c None",
+". c #000000000000",
+"X c #FFFFFFFFFFFF",
+" ",
+" ...... ",
+" .XXX.X. ",
+" .XXX.XX. ",
+" .XXX.XXX. ",
+" .XXX..... ",
+" .XXXXXXX. ",
+" .XXXXXXX. ",
+" .XXXXXXX. ",
+" .XXXXXXX. ",
+" .XXXXXXX. ",
+" .XXXXXXX. ",
+" .XXXXXXX. ",
+" ......... ",
+" ",
+" "};
+
+
+/* quando invocata (con il segnale delete_event), termina l'applicazione. */
+void close_application( GtkWidget *widget, gpointer *data ) {
+ gtk_main_quit();
+}
+
+
+/* invocata se il bottone &egrave; clickato. Stampa semplicemente un messaggio */
+void button_clicked( GtkWidget *widget, gpointer *data ) {
+ printf( "button clicked\n" );
+}
+
+
+
+
+int main( int argc, char *argv[] )
+{
+ /* i widget sono memorizzati nel tipo GtkWidget */
+ GtkWidget *window, *pixmapwid, *button;
+ GdkPixmap *pixmap;
+ GdkBitmap *mask;
+ GtkStyle *style;
+
+ /* crea la finestra principale, e collega il segnale delete_event
+ alla terminazione dell'applicazione */
+ gtk_init( &amp;argc, &amp;argv );
+ window = gtk_window_new( GTK_WINDOW_TOPLEVEL );
+ gtk_signal_connect( GTK_OBJECT (window), "delete_event",
+ GTK_SIGNAL_FUNC (close_application), NULL );
+ gtk_container_border_width( GTK_CONTAINER (window), 10 );
+ gtk_widget_show( window );
+
+ /* la pixmap proviene da gdk */
+ style = gtk_widget_get_style( window );
+ pixmap = gdk_pixmap_create_from_xpm_d( window->window, &amp;mask,
+ &amp;style->bg[GTK_STATE_NORMAL],
+ (gchar **)xpm_data );
+
+ /* un widget pixmap per contenere la pixmap */
+ pixmapwid = gtk_pixmap_new( pixmap, mask );
+ gtk_widget_show( pixmapwid );
+
+ /* un bottone per contenere il widget pixmap */
+ button = gtk_button_new();
+ gtk_container_add( GTK_CONTAINER(button), pixmapwid );
+ gtk_container_add( GTK_CONTAINER(window), button );
+ gtk_widget_show( button );
+
+ gtk_signal_connect( GTK_OBJECT(button), "clicked",
+ GTK_SIGNAL_FUNC(button_clicked), NULL );
+
+ /* mostra la finestra */
+ gtk_main ();
+
+ return 0;
+}
+</verb></tscreen>
+
+
+Per caricare una pixmap da un file XPM chiamato icon0.xpm che si trova
+nella direttorio corrente, avremmo creato la pixmap in questo modo:
+
+<tscreen><verb>
+ /* carica una pixmap da un file */
+ pixmap = gdk_pixmap_create_from_xpm( window->window, &amp;mask,
+ &amp;style->bg[GTK_STATE_NORMAL],
+ "./icon0.xpm" );
+ pixmapwid = gtk_pixmap_new( pixmap, mask );
+ gtk_widget_show( pixmapwid );
+ gtk_container_add( GTK_CONTAINER(window), pixmapwid );
+</verb></tscreen>
+
+
+Usare le Sagome
+<p>
+Uno degli svantaggi di usare le pixmap &egrave; costituito dal fatto che l'oggetto
+mostrato &egrave; sempre rettangolare, a prescindere dall'immagine. Ci piacerebbe
+invece poter crare dei desktop e delle immagini con forme pi&ugrave; naturali. Per
+esempio, per l'interfaccia di un gioco, potremmo volere avere dei pulsanti
+circolari. Il modo per ottenere questo effetto &egrave; di usare delle finestre
+sagomate.
+
+Una finestra sagomata &egrave; semplicemente una pixmap in cui i pixel dello
+sfondo sono trasparenti. In questo modo, se l'immagine di sfondo &egrave;
+multicolore, possiamo evitare di sovrascriverla con un bordo rettangolare
+attorno all'icona. Il prossimo esempio mostra una carriola sul desktop.
+
+<tscreen><verb>
+
+#include <gtk/gtk.h>
+
+
+
+/* XPM */
+static char * WheelbarrowFull_xpm[] = {
+"48 48 64 1",
+" c None",
+". c #DF7DCF3CC71B",
+"X c #965875D669A6",
+"o c #71C671C671C6",
+"O c #A699A289A699",
+"+ c #965892489658",
+"@ c #8E38410330C2",
+"# c #D75C7DF769A6",
+"$ c #F7DECF3CC71B",
+"% c #96588A288E38",
+"&amp; c #A69992489E79",
+"* c #8E3886178E38",
+"= c #104008200820",
+"- c #596510401040",
+"; c #C71B30C230C2",
+": c #C71B9A699658",
+"> c #618561856185",
+", c #20811C712081",
+"< c #104000000000",
+"1 c #861720812081",
+"2 c #DF7D4D344103",
+"3 c #79E769A671C6",
+"4 c #861782078617",
+"5 c #41033CF34103",
+"6 c #000000000000",
+"7 c #49241C711040",
+"8 c #492445144924",
+"9 c #082008200820",
+"0 c #69A618611861",
+"q c #B6DA71C65144",
+"w c #410330C238E3",
+"e c #CF3CBAEAB6DA",
+"r c #71C6451430C2",
+"t c #EFBEDB6CD75C",
+"y c #28A208200820",
+"u c #186110401040",
+"i c #596528A21861",
+"p c #71C661855965",
+"a c #A69996589658",
+"s c #30C228A230C2",
+"d c #BEFBA289AEBA",
+"f c #596545145144",
+"g c #30C230C230C2",
+"h c #8E3882078617",
+"j c #208118612081",
+"k c #38E30C300820",
+"l c #30C2208128A2",
+"z c #38E328A238E3",
+"x c #514438E34924",
+"c c #618555555965",
+"v c #30C2208130C2",
+"b c #38E328A230C2",
+"n c #28A228A228A2",
+"m c #41032CB228A2",
+"M c #104010401040",
+"N c #492438E34103",
+"B c #28A2208128A2",
+"V c #A699596538E3",
+"C c #30C21C711040",
+"Z c #30C218611040",
+"A c #965865955965",
+"S c #618534D32081",
+"D c #38E31C711040",
+"F c #082000000820",
+" ",
+" .XoO ",
+" +@#$%o&amp; ",
+" *=-;#::o+ ",
+" >,<12#:34 ",
+" 45671#:X3 ",
+" +89<02qwo ",
+"e* >,67;ro ",
+"ty> 459@>+&amp;&amp; ",
+"$2u+ ><ipas8* ",
+"%$;=* *3:.Xa.dfg> ",
+"Oh$;ya *3d.a8j,Xe.d3g8+ ",
+" Oh$;ka *3d$a8lz,,xxc:.e3g54 ",
+" Oh$;kO *pd$%svbzz,sxxxxfX..&amp;wn> ",
+" Oh$@mO *3dthwlsslszjzxxxxxxx3:td8M4 ",
+" Oh$@g&amp; *3d$XNlvvvlllm,mNwxxxxxxxfa.:,B* ",
+" Oh$@,Od.czlllllzlmmqV@V#V@fxxxxxxxf:%j5&amp; ",
+" Oh$1hd5lllslllCCZrV#r#:#2AxxxxxxxxxcdwM* ",
+" OXq6c.%8vvvllZZiqqApA:mq:Xxcpcxxxxxfdc9* ",
+" 2r<6gde3bllZZrVi7S@SV77A::qApxxxxxxfdcM ",
+" :,q-6MN.dfmZZrrSS:#riirDSAX@Af5xxxxxfevo",
+" +A26jguXtAZZZC7iDiCCrVVii7Cmmmxxxxxx%3g",
+" *#16jszN..3DZZZZrCVSA2rZrV7Dmmwxxxx&amp;en",
+" p2yFvzssXe:fCZZCiiD7iiZDiDSSZwwxx8e*>",
+" OA1<jzxwwc:$d%NDZZZZCCCZCCZZCmxxfd.B ",
+" 3206Bwxxszx%et.eaAp77m77mmmf3&amp;eeeg* ",
+" @26MvzxNzvlbwfpdettttttttttt.c,n&amp; ",
+" *;16=lsNwwNwgsvslbwwvccc3pcfu<o ",
+" p;<69BvwwsszslllbBlllllllu<5+ ",
+" OS0y6FBlvvvzvzss,u=Blllj=54 ",
+" c1-699Blvlllllu7k96MMMg4 ",
+" *10y8n6FjvllllB<166668 ",
+" S-kg+>666<M<996-y6n<8* ",
+" p71=4 m69996kD8Z-66698&amp;&amp; ",
+" &amp;i0ycm6n4 ogk17,0<6666g ",
+" N-k-<> >=01-kuu666> ",
+" ,6ky&amp; &amp;46-10ul,66, ",
+" Ou0<> o66y<ulw<66&amp; ",
+" *kk5 >66By7=xu664 ",
+" <<M4 466lj<Mxu66o ",
+" *>> +66uv,zN666* ",
+" 566,xxj669 ",
+" 4666FF666> ",
+" >966666M ",
+" oM6668+ ",
+" *4 ",
+" ",
+" "};
+
+
+/* quando invocata (con il segnale delete_event), termina l'applicazione. */
+void close_application( GtkWidget *widget, gpointer *data ) {
+ gtk_main_quit();
+}
+
+
+int main (int argc, char *argv[])
+{
+ /* il tipo di dato per i widget &egrave; GtkWidget */
+ GtkWidget *window, *pixmap, *fixed;
+ GdkPixmap *gdk_pixmap;
+ GdkBitmap *mask;
+ GtkStyle *style;
+ GdkGC *gc;
+
+ /* crea la finestra principale e collega il segnale delete_event per
+ terminare l'applicazione. Notare che non mettiamo un titolo
+ alla finestra. */
+ gtk_init (&amp;argc, &amp;argv);
+ window = gtk_window_new( GTK_WINDOW_POPUP );
+ gtk_signal_connect (GTK_OBJECT (window), "delete_event",
+ GTK_SIGNAL_FUNC (close_application), NULL);
+ gtk_widget_show (window);
+
+ /* ora occupiamoci della pixmap e del widget pixmap */
+ style = gtk_widget_get_default_style();
+ gc = style->black_gc;
+ gdk_pixmap = gdk_pixmap_create_from_xpm_d( window->window, &amp;mask,
+ &amp;style->bg[GTK_STATE_NORMAL],
+ WheelbarrowFull_xpm );
+ pixmap = gtk_pixmap_new( gdk_pixmap, mask );
+ gtk_widget_show( pixmap );
+
+ /* Per mostrare la pixmap, usiamo un widget "fixed" in cui metterla */
+ fixed = gtk_fixed_new();
+ gtk_widget_set_usize( fixed, 200, 200 );
+ gtk_fixed_put( GTK_FIXED(fixed), pixmap, 0, 0 );
+ gtk_container_add( GTK_CONTAINER(window), fixed );
+ gtk_widget_show( fixed );
+
+ /* Questa maschera tutto tranne l'immagine stessa */
+ gtk_widget_shape_combine_mask( window, mask, 0, 0 );
+
+ /* mostra la finestra */
+ gtk_widget_set_uposition( window, 20, 400 );
+ gtk_widget_show( window );
+ gtk_main ();
+
+ return 0;
+}
+</verb></tscreen>
+<p>
+Per rendere sensibile l'immagine della carriola, potremmo collegare
+il segnale di pressione del bottone in modo che venga compiuta una certa
+azione. Le prossime linee renderebbero l'immagine sensibile alla pressione
+di un bottone del mouse che fa s&igrave; che l'applicazione termini.
+
+<tscreen><verb>
+gtk_widget_set_events( window,
+ gtk_widget_get_events( window ) |
+ GDK_BUTTON_PRESS_MASK );
+
+gtk_signal_connect( GTK_OBJECT(window), "button_press_event",
+ GTK_SIGNAL_FUNC(close_application), NULL );
+</verb></tscreen>
+
+
+<sect> Widget Contenitore
+
+<sect1> Il widget Blocco Note (Notebook)
+<p>
+Il widget Blocco note &egrave; un insieme di pagine sovrapposte l'una con l'altra,
+ognuna contente cose diverse. Questo widget &egrave; diventato molto comune nella
+programmazione delle interfacce utente ed &egrave; un buon metodo per mostrare informazioni
+tra loro correlate ma che debbano essere mostrate separatamente.
+
+<p>
+La prima funzione da invocare che si deve conoscere, come si pu&ograve; intuire, &egrave; usata
+per creare un nuovo Blocco Note.
+
+<tscreen><verb>
+GtkWidget* gtk_notebook_new (void);
+</verb></tscreen>
+
+Una volta che il notebook &egrave; sato creato, ci sono 12 funzioni che possono
+operare sul widget notebook. Guardiamole individualmente.
+
+La prima che vediamo riguarda come posizionare l'indicatore di pagina.
+Questi inidicatori di pagina o ``linguette'' (come possono anche essere chiamati)
+possono essere posizionati in quattro posti: alto, basso, sinistra.destra.
+
+<tscreen><verb>
+void gtk_notebook_set_tab_pos (GtkNotebook *notebook, GtkPositionType pos);
+</verb></tscreen>
+
+GtkPositionType sar&agrave; uno dei seguenti valori (molto autoesplicativi)
+<itemize>
+<item> GTK_POS_LEFT
+<item> GTK_POS_RIGHT
+<item> GTK_POS_TOP
+<item> GTK_POS_BOTTOM
+</itemize>
+
+GTK_POS_TOP e' il valore predefinito.
+
+Ora vediamo come aggiugere le pagine al Blocco Note. Ci sono 3 modi per farlo. Diamo
+un'occhiata ai primi due insieme, viste che sono molto simili.
+
+<tscreen><verb>
+void gtk_notebook_append_page (GtkNotebook *notebook, GtkWidget *child, GtkWidget *tab_label);
+
+void gtk_notebook_prepend_page (GtkNotebook *notebook, GtkWidget *child, GtkWidget *tab_label);
+</verb></tscreen>
+
+Queste funzioni aggiungono pagine al notebook inserendole rispettivamente alla fine
+(append) o all'inizio (prepend). *child &egrave; il widget che &egrave; posto nella pagina del
+notebook e *tab_label e la intestazione della pagina stessa.
+
+L'ultima funzione per aggiungere una pagina al notebook contiene tutte le propriet&agrave;
+delle precedenti due, ma permette di specificare dove posizionare la pagina che
+si vuole inserire.
+
+<tscreen><verb>
+void gtk_notebook_insert_page (GtkNotebook *notebook, GtkWidget *child, GtkWidget *tab_label, gint position);
+</verb></tscreen>
+
+I parametri sono gli stessi di _append_ e _prepend_ tranne che per il parametro in
+pi&ugrave;: ``position''.
+Questo parametro viene usato per specificare in che posizione ineserire la pagina.
+
+Ora che conosciamo come aggiungere le pagine, vediamo come poter toglierne una.
+
+<tscreen><verb>
+void gtk_notebook_remove_page (GtkNotebook *notebook, gint page_num);
+</verb></tscreen>
+
+Questa funzione prende il numero della pagina specificata dal campo page_num e
+rimuove la pagina corrispondente dal Blocco Note.
+
+Per trovare qual'&egrave; la pagina corrente nel notebook bisogna usare la funzione:
+
+<tscreen><verb>
+gint gtk_notebook_current_page (GtkNotebook *notebook);
+</verb></tscreen>
+
+Le prossime due funzioni sono semplicemente delle chiamate che muovono la pagina del
+notebook avanti o indietro. Semplicemente forniscono le chiamate alle rispettive
+funzioni del widget notebook su si pu&ograve; operare. NB: quando un notebook &egrave;
+correntemente sull'ultima pagina e viene invocata la funzione gtk_notebook_next_page,
+il notebook ritorner&agrave; automaticamente alla prima pagina. Logicamente succede anche
+il contrario quando invochi gtk_notebook_prev_page e ti trovi sulla prima pagina.
+
+<tscreen><verb>
+void gtk_notebook_next_page (GtkNoteBook *notebook);
+void gtk_notebook_prev_page (GtkNoteBook *notebook);
+</verb></tscreen>
+
+La prossima funzione stabilisce la pagina ``attiva''. Se si vuole che la pagina
+principale del notebook sia per esempio la 5 (ad esempio) si pu&ograve; usare questa
+funzione.
+Se non si usa questa funzione la pagina principale sar&agrave; la 1.
+
+<tscreen><verb>
+void gtk_notebook_set_page (GtkNotebook *notebook, gint page_num);
+</verb></tscreen>
+
+Le prossime due funzioni aggiungono o rimuovono, rispettivamente, le intestazioni e
+i bordi delle pagine.
+
+<tscreen><verb>
+void gtk_notebook_set_show_tabs (GtkNotebook *notebook, gint show_tabs);
+void gtk_notebook_set_show_border (GtkNotebook *notebook, gint show_border);
+</verb></tscreen>
+
+show_tabs e show_border posso avere come valore TRUE o FALSE (0 or 1).
+
+Diamo ora una occhiata ad un esempio. Si tratta di una espansione del codice preso
+dal file testgtk.c che &egrave; compreso in tutte le distribuzioni, e mostra
+tutte le 13 funzioni. Questo piccolo programma crea una finestra con un notebook
+e 6 bottoni. Il notebook contiene 11 pagine, aggiunte nei 3 modi differenti (alla
+fine, all'inizio o in qualsiasi posizione). I bottoni permettono di girare le
+intestazioni, aggiungere/rimuovere le intestazioni e i bordi, rimuovere una
+pagina, cambiare la pagina avanti e indietro e uscire dal programma.
+
+<tscreen><verb>
+
+#include <gtk/gtk.h>
+
+/* Queta funzione ruota le posizione delle linguette delle pagine */
+void rotate_book (GtkButton *button, GtkNotebook *notebook)
+{
+ gtk_notebook_set_tab_pos (notebook, (notebook->tab_pos +1) %4);
+}
+
+/* Aggiunge e rimuove le linguette e i bordi */
+void tabsborder_book (GtkButton *button, GtkNotebook *notebook)
+{
+ gint tval = FALSE;
+ gint bval = FALSE;
+ if (notebook->show_tabs == 0)
+ tval = TRUE;
+ if (notebook->show_border == 0)
+ bval = TRUE;
+
+ gtk_notebook_set_show_tabs (notebook, tval);
+ gtk_notebook_set_show_border (notebook, bval);
+}
+
+/* Rimuove una pagina */
+void remove_book (GtkButton *button, GtkNotebook *notebook)
+{
+ gint page;
+
+ page = gtk_notebook_current_page(notebook);
+ gtk_notebook_remove_page (notebook, page);
+ /* E' necessario fare un refresh del widget --
+ Questo forza il widget a ridisegnarsi. */
+ gtk_widget_draw(GTK_WIDGET(notebook), NULL);
+}
+
+void delete (GtkWidget *widget, gpointer *data)
+{
+ gtk_main_quit ();
+}
+
+int main (int argc, char *argv[])
+{
+ GtkWidget *window;
+ GtkWidget *button;
+ GtkWidget *table;
+ GtkWidget *notebook;
+ GtkWidget *frame;
+ GtkWidget *label;
+ GtkWidget *checkbutton;
+ int i;
+ char bufferf[32];
+ char bufferl[32];
+
+ gtk_init (&amp;argc, &amp;argv);
+
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+
+ gtk_signal_connect (GTK_OBJECT (window), "destroy",
+ GTK_SIGNAL_FUNC (destroy), NULL);
+
+ gtk_container_border_width (GTK_CONTAINER (window), 10);
+
+ table = gtk_table_new(2,6,TRUE);
+ gtk_container_add (GTK_CONTAINER (window), table);
+
+ /* Crea un nuovo notebook, e tabilisce la posizione delle linguette */
+ notebook = gtk_notebook_new ();
+ gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), GTK_POS_TOP);
+ gtk_table_attach_defaults(GTK_TABLE(table), notebook, 0,6,0,1);
+ gtk_widget_show(notebook);
+
+ /* appende una parte delle pagine */
+ for (i=0; i < 5; i++) {
+ sprintf(bufferf, "Append Frame %d", i+1);
+ sprintf(bufferl, "Page %d", i+1);
+
+ frame = gtk_frame_new (bufferf);
+ gtk_container_border_width (GTK_CONTAINER (frame), 10);
+ gtk_widget_set_usize (frame, 100, 75);
+ gtk_widget_show (frame);
+
+ label = gtk_label_new (bufferf);
+ gtk_container_add (GTK_CONTAINER (frame), label);
+ gtk_widget_show (label);
+
+ label = gtk_label_new (bufferl);
+ gtk_notebook_append_page (GTK_NOTEBOOK (notebook), frame, label);
+ }
+
+
+ /* Ora aggiungiamo una pagina in una certa posizione */
+ checkbutton = gtk_check_button_new_with_label ("Check me please!");
+ gtk_widget_set_usize(checkbutton, 100, 75);
+ gtk_widget_show (checkbutton);
+
+ label = gtk_label_new ("Add spot");
+ gtk_container_add (GTK_CONTAINER (checkbutton), label);
+ gtk_widget_show (label);
+ label = gtk_label_new ("Add page");
+ gtk_notebook_insert_page (GTK_NOTEBOOK (notebook), checkbutton, label, 2);
+
+ /* Ora finalmente aggiungiamo le pagine all'inizio */
+ for (i=0; i < 5; i++) {
+ sprintf(bufferf, "Prepend Frame %d", i+1);
+ sprintf(bufferl, "PPage %d", i+1);
+
+ frame = gtk_frame_new (bufferf);
+ gtk_container_border_width (GTK_CONTAINER (frame), 10);
+ gtk_widget_set_usize (frame, 100, 75);
+ gtk_widget_show (frame);
+
+ label = gtk_label_new (bufferf);
+ gtk_container_add (GTK_CONTAINER (frame), label);
+ gtk_widget_show (label);
+
+ label = gtk_label_new (bufferl);
+ gtk_notebook_prepend_page (GTK_NOTEBOOK(notebook), frame, label);
+ }
+
+ /* Stabilisce quale sar&agrave; la prima pagina che sar&agrave; visualizzata. */
+ gtk_notebook_set_page (GTK_NOTEBOOK(notebook), 3);
+
+
+ /* Crea un set di bottoni */
+ button = gtk_button_new_with_label ("close");
+ gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
+ GTK_SIGNAL_FUNC (destroy), NULL);
+ gtk_table_attach_defaults(GTK_TABLE(table), button, 0,1,1,2);
+ gtk_widget_show(button);
+
+ button = gtk_button_new_with_label ("next page");
+ gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
+ (GtkSignalFunc) gtk_notebook_next_page,
+ GTK_OBJECT (notebook));
+ gtk_table_attach_defaults(GTK_TABLE(table), button, 1,2,1,2);
+ gtk_widget_show(button);
+
+ button = gtk_button_new_with_label ("prev page");
+ gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
+ (GtkSignalFunc) gtk_notebook_prev_page,
+ GTK_OBJECT (notebook));
+ gtk_table_attach_defaults(GTK_TABLE(table), button, 2,3,1,2);
+ gtk_widget_show(button);
+
+ button = gtk_button_new_with_label ("tab position");
+ gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
+ (GtkSignalFunc) rotate_book, GTK_OBJECT(notebook));
+ gtk_table_attach_defaults(GTK_TABLE(table), button, 3,4,1,2);
+ gtk_widget_show(button);
+
+ button = gtk_button_new_with_label ("tabs/border on/off");
+ gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
+ (GtkSignalFunc) tabsborder_book,
+ GTK_OBJECT (notebook));
+ gtk_table_attach_defaults(GTK_TABLE(table), button, 4,5,1,2);
+ gtk_widget_show(button);
+
+ button = gtk_button_new_with_label ("remove page");
+ gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
+ (GtkSignalFunc) remove_book,
+ GTK_OBJECT(notebook));
+ gtk_table_attach_defaults(GTK_TABLE(table), button, 5,6,1,2);
+ gtk_widget_show(button);
+
+ gtk_widget_show(table);
+ gtk_widget_show(window);
+
+ gtk_main ();
+
+ return 0;
+}
+</verb></tscreen>
+<p>
+E speriamo che questo vi aiuti a creare i Blocco Note per le vostre applicazioni GTK!
+
+<sect1> Finestre Scorribili (Scrolled Windows)
+<p>
+Le Finestre Scorribili sono usate per creare areee scorribili in una vera finestra.
+Si pu&ograve; inserire qualsiasi tipo di widget in questo tipo di finestra, e possono poi
+essere accessibili a prescindere dalle dimensioni usando le barre di scorrimento.
+
+La funzione seguente &egrave; usata per creare una nuova scrolled window.
+
+<tscreen><verb>
+GtkWidget* gtk_scrolled_window_new (GtkAdjustment *hadjustment,
+ GtkAdjustment *vadjustment);
+</verb></tscreen>
+<p>
+Il primo argomento &egrave; l'aggiustamento (di quanto scendere ogni
+volta) orizzontale e il secondo &egrave; quello verticale. A questi si assegna
+quasi sempre il valore NULL.
+
+<tscreen><verb>
+void gtk_scrolled_window_set_policy (GtkScrolledWindow *scrolled_window,
+ GtkPolicyType hscrollbar_policy,
+ GtkPolicyType vscrollbar_policy);
+</verb></tscreen>
+
+Questa funzione stabilisce la politica da usare nella barra di scorrimento. Il primo
+argomento &egrave; la finestra scorribile interessata. Il secondo stabilisce la politica
+per la barra di scorrimento orizzontale e il terzo &egrave; quello per la politca verticale.
+
+La politica pu&ograve; essere GTK_POLICY AUTOMATIC o GTK_POLICY_ALWAYS.
+GTK_POLICY_AUTOMATIC decide automaticamente se la barra di scorrimento deve essere
+visualizzata, mentre con GTK_POLICY_ALWAYS la barra verr&agrave; sempre mostrata.
+
+<tscreen><verb>
+#include <gtk/gtk.h>
+
+void destroy(GtkWidget *widget, gpointer *data)
+{
+ gtk_main_quit();
+}
+
+int main (int argc, char *argv[])
+{
+ static GtkWidget *window;
+ GtkWidget *scrolled_window;
+ GtkWidget *table;
+ GtkWidget *button;
+ char buffer[32];
+ int i, j;
+
+ gtk_init (&amp;argc, &amp;argv);
+
+ /* Crea una nuove finestra di dialogo in cui la scrolled window sar&agrave;
+ inserita. Una finestra di dialogo &egrave; semplicemente come una
+ finestra normale, ma ha anche un vbox e un separatore orizzontale
+ gi&agrave; inseriti per difetto. E'un modo semplice per
+ creare finestre di dialogo. */
+ window = gtk_dialog_new ();
+ gtk_signal_connect (GTK_OBJECT (window), "destroy",
+ (GtkSignalFunc) destroy, NULL);
+ gtk_window_set_title (GTK_WINDOW (window), "dialog");
+ gtk_container_border_width (GTK_CONTAINER (window), 0);
+
+ /* crea una nuova finestra scorribile. */
+ scrolled_window = gtk_scrolled_window_new (NULL, NULL);
+
+ gtk_container_border_width (GTK_CONTAINER (scrolled_window), 10);
+
+ /* la politica &egrave; GTK_POLICY AUTOMATIC per lo scorrimento orizzontale e
+ GTK_POLICY_ALWAYS per quello verticale. */
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
+ GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
+
+ /* La finestra di dialogo &egrave; creata con un vbox gi&agrave; inserito.*/
+ gtk_box_pack_start (GTK_BOX (GTK_DIALOG(window)->vbox), scrolled_window,
+ TRUE, TRUE, 0);
+ gtk_widget_show (scrolled_window);
+
+ /* crea una tablella di10 x 10. */
+ table = gtk_table_new (10, 10, FALSE);
+
+ /* setta lo spazio tra ogni cella di 10 pixel sia verticale sia orizzontale*/
+ gtk_table_set_row_spacings (GTK_TABLE (table), 10);
+ gtk_table_set_col_spacings (GTK_TABLE (table), 10);
+
+ /* inserisce la tabella nella finestra scorribile*/
+ gtk_container_add (GTK_CONTAINER (scrolled_window), table);
+ gtk_widget_show (table);
+
+ /* questo semplicemente crea una griglia di bottoni nella tabelle per
+ dimostrare il comportamento della finestra scorribile */
+ for (i = 0; i < 10; i++)
+ for (j = 0; j < 10; j++) {
+ sprintf (buffer, "button (%d,%d)\n", i, j);
+ button = gtk_toggle_button_new_with_label (buffer);
+ gtk_table_attach_defaults (GTK_TABLE (table), button,
+ i, i+1, j, j+1);
+ gtk_widget_show (button);
+ }
+
+ /* Aggiunge un bottone "close" alla fine della finestra */
+ button = gtk_button_new_with_label ("close");
+ gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
+ (GtkSignalFunc) gtk_widget_destroy,
+ GTK_OBJECT (window));
+
+ /* questo fa s&igrave; che questo bottone sia quello predefinito */
+
+ GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
+ gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area), button, TRUE, TRUE, 0);
+
+ /* Questo ottiene il bottone predefinito. Premendo semplicemente l'"enter" il
+ bottone si avvier&agrave; */
+ gtk_widget_grab_default (button);
+ gtk_widget_show (button);
+
+ gtk_widget_show (window);
+
+ gtk_main();
+
+ return(0);
+}
+</verb></tscreen>
+<p>
+Prova a giocare con il ridemensionamento della finestra. Noterete la reazione della
+barra di scorrimento. Potete anche usare la funzione gtk_widget_set_usize() per
+assegnare la dimensione predefinita della finestra o di un widget.
+<!-- (ndMichel: questa chiamata non funziona per i bottoni!) -->
+
+
+<sect> Il Widgets Lista
+<p>
+Il widget GtkList serve come contenitore verticale per altri widget che
+devono essere di tipo GtkListItem.
+
+Un widget GtkList possiede una sua propria finestra per ricevere eventi
+e un suo proprio colore di sfondo che di solito &egrave; bianco. Dal momento
+che &egrave; direttamente derivato dal widget GtkContainer, pu&ograve; essere trattato
+come tale usando la macro GTK_CONTAINER(List); si veda il widget GtkContainer
+per ulteriori dettagli.
+Per usare il widget GtkList in tutte le sue potenzialit&agrave;, si dovrebbe essere
+gi&agrave; familiari con l'uso della GList e delle relative funzioni g_list_*().
+
+All'interno della definizione della struttura del widget GtkList c'&egrave; un
+campo che sar&agrave; per noi di grande interesse, cio&egrave;:
+
+<tscreen><verb>
+struct _GtkList
+{
+ ...
+ GList *selection;
+ guint selection_mode;
+ ...
+};
+</verb></tscreen>
+
+Il campo ``selection'' in un GtkList punta a una lista collegata di tutti
+gli elementi che sono selezionati correntemente, oppure a NULL se la
+selezione &egrave; vuota. Quindi, per avere informazioni sulla selezione corrente,
+leggiamo il campo GTK_LIST()->selection, senza per&ograve; modificarlo dal momento
+che i campi interni debbono essere gestiti dalle funzioni gtk_list_*().
+
+Le modalit&agrave; di selezione in una GtkList, e quindi il contenuto di
+GTK_LIST()->selection, sono determinate dal campo selection_mode:
+
+selection_mode pu&ograve; assumere uno dei seguenti valori:
+<itemize>
+<item> GTK_SELECTION_SINGLE - La selezione pu&ograve; essere o NULL oppure
+ un puntatore GList* per un singolo elemento
+ selezionato.
+
+<item> GTK_SELECTION_BROWSE - La selezione &egrave; null se la lista non contiene
+ alcun widget o se ha solo widget non sensibili,
+ oppure pu&ograve; contenere un puntatore a una struttura
+ GList, e quindi esattamente un elemento di lista.
+
+<item> GTK_SELECTION_MULTIPLE - La selezione &egrave; ``NULL'' se non &egrave; selezionato
+ alcun elemento di lista, oppure un puntatore GList al
+ primo elemento selezionato. Quello, a sua volta, punta
+ a una struttura GList per il secondo elemento selezionato
+ e cos&igrave; via.
+
+<item> GTK_SELECTION_EXTENDED - La selezione &egrave; sempre NULL.
+</itemize>
+<p>
+Il valore per difetto &egrave; GTK_SELECTION_MULTIPLE.
+
+<sect1> Segnali
+<p>
+<tscreen><verb>
+void GtkList::selection_changed (GtkList *LIST)
+</verb></tscreen>
+
+Questo segnale verr&agrave; invocato ogni volta che il campo di
+selezione di una GtkList &egrave; cambiato. Questo accade quando
+un figlio della GtkList viene selezionato o deselezionato.
+
+<tscreen><verb>
+void GtkList::select_child (GtkList *LIST, GtkWidget *CHILD)
+</verb></tscreen>
+
+Questo segnale viene invocato quando un fuglio di una GtkList
+sta per essere selezionato. Questo accade principalmente in
+occasione di chiamate a gtk_list_select_item() e gtk_list_select_child(),
+di pressioni di bottoni e a volte pu&ograve; venir fatto scattare indirettamente
+in altre occasioni, in cui vengono aggiunti o rimossi dei figli
+dalla GtkList.
+
+<tscreen><verb>
+void GtkList::unselect_child (GtkList *LIST, GtkWidget *CHILD)
+</verb></tscreen>
+
+Questo segnale viene invocato quando un figlio della GtkList sta
+per essere deselezionato. Ci&ograve; accade principalmente in occasione
+di chiamate a gtk_list_unselect_item() e gtk_list_unselect_child(),
+di pressioni di bottoni, e a volte pu&ograve; venir fatto scattare indirettamente
+in altre occasioni, in cui vengono aggiunti o rimossi dei figli
+dalla GtkList.
+
+<sect1> Funzioni
+<p>
+<tscreen><verb>
+guint gtk_list_get_type (void)
+</verb></tscreen>
+
+Restituisce l'identificatore di tipo `GtkList'.
+
+<tscreen><verb>
+GtkWidget* gtk_list_new (void)
+</verb></tscreen>
+
+Crea un nuovo oggetto `GtkList'. Il nuovo widget viene
+restituito sotto forma di un puntoatore ad un oggetto
+`GtkWidget&igrave;'. In caso di fallimento, viene ritornato NULL.
+
+<tscreen><verb>
+void gtk_list_insert_items (GtkList *LIST, GList *ITEMS, gint POSITION)
+</verb></tscreen>
+
+Inserisce degli elementi di lista nella LIST, a partire da
+POSITION. ITEMS ITEMS &egrave; una lista doppiamente collegata, in
+cui ci si aspetta che i puntatori di ogni nodo puntino a
+un GtkListItem appena creato. I nodi GList di ITEMS vengono
+assunti dalla LIST.
+
+<tscreen><verb>
+void gtk_list_append_items (GtkList *LIST, GList *ITEMS)
+</verb></tscreen>
+
+Inserisce elementi di lista proprio come gtk_list_insert_items(),
+ma alla fine della LIST. I nodi GList di ITEMS vengono
+assunti dalla LIST.
+
+<tscreen><verb>
+void gtk_list_prepend_items (GtkList *LIST, GList *ITEMS)
+</verb></tscreen>
+
+Inserisce elementi di lista proprio come gtk_list_insert_items(),
+ma al principio della LIST. I nodi GList di ITEMS vengono
+assunti dalla LIST.
+
+<tscreen><verb>
+void gtk_list_remove_items (GtkList *LIST, GList *ITEMS)
+</verb></tscreen>
+
+Rimuove degli elementi di lista dalla LIST. ITEMS &egrave; una lista
+doppiamente collegata in cui ci si aspetta che i puntatori di
+ogni nodo puntino a un figlio diretto di LIST. E' poi responsabilit&agrave;
+del chiamante di fare una chiamata a g_list_free(ITEMS). E' anche
+necessario che il chiamante distrugga lui stesso gli elementi della
+lista.
+
+<tscreen><verb>
+void gtk_list_clear_items (GtkList *LIST, gint START, gint END)
+</verb></tscreen>
+
+Rimuove e distrugge elementi di lista da LIST. Un widget ne &egrave;
+interessato se la sua posizione corrente all'interno di LIST &egrave; compreso
+fra START ed END.
+
+<tscreen><verb>
+void gtk_list_select_item (GtkList *LIST, gint ITEM)
+</verb></tscreen>
+
+Invoca il segnale GtkList::select_child per un elemento di lista
+specificato dalla sua posizione corrente all'interno di LIST.
+
+<tscreen><verb>
+void gtk_list_unselect_item (GtkList *LIST, gint ITEM)
+</verb></tscreen>
+
+Invoca il segnale GtkList::unselect_child per un elemento di lista
+specificato dalla sua posizione corrente all'interno di LIST.
+
+<tscreen><verb>
+void gtk_list_select_child (GtkList *LIST, GtkWidget *CHILD)
+</verb></tscreen>
+
+Invoca il segnale GtkList::select_child per uno specifico CHILD.
+
+<tscreen><verb>
+void gtk_list_unselect_child (GtkList *LIST, GtkWidget *CHILD)
+</verb></tscreen>
+
+Invoca il segnale GtkList::unselect_child per uno specifico CHILD.
+
+<tscreen><verb>
+gint gtk_list_child_position (GtkList *LIST, GtkWidget *CHILD)
+</verb></tscreen>
+
+Restituisce la posizione di CHILD all'interno di LIST. In caso di fallimento,
+viene restituito `-1'.
+
+<tscreen><verb>
+void gtk_list_set_selection_mode (GtkList *LIST, GtkSelectionMode MODE)
+</verb></tscreen>
+
+Assegna a LIST il modo di selezione MODE, che pu&ograve; essere uno fra
+GTK_SELECTION_SINGLE, GTK_SELECTION_BROWSE, GTK_SELECTION_MULTIPLE o
+GTK_SELECTION_EXTENDED.
+
+<tscreen><verb>
+GtkList* GTK_LIST (gpointer OBJ)
+</verb></tscreen>
+
+Fa il cast di un generico puntatore a `GtkList*'. Per maggiori
+informazioni vedere Standard Macros::.
+
+<tscreen><verb>
+GtkListClass* GTK_LIST_CLASS (gpointer CLASS)
+</verb></tscreen>
+
+Fa il cast di un generico puntatore a `GtkListClass*'. Per maggiori
+informazioni vedere Standard Macros::.
+
+<tscreen><verb>
+gint GTK_IS_LIST (gpointer OBJ)
+</verb></tscreen>
+
+Determina se un generico puntatore si riferisce ad un oggetto `GtkList'.
+Per maggiori informazioni vedere Standard Macros::.
+
+
+<sect1> Esempio
+<p>
+Diamo di seguito un programma di esempio che stamper&agrave; i campbiamenti
+della selezione di una GtkList, e vi lascia ``imprigionare'' gli elementi
+di una lista selezionandoli con il pulsante destro del mouse:
+
+<tscreen><verb>
+/* compilate questo programma con:
+ * $ gcc -I/usr/local/include/ -lgtk -lgdk -lglib -lX11 -lm -Wall main.c
+ */
+
+/* includiamo i file header di gtk+
+ * includiamo stdio.h, ne abbiamo bisogno per printf()
+ */
+#include <gtk/gtk.h>
+#include <stdio.h>
+
+/* Questa e' la nostra stringa di identificazione dei dati per assegnarli
+ * ad elementi di lista
+ */
+const gchar *list_item_data_key="list_item_data";
+
+
+/* prototipi per i gestori di segnale che connetteremo
+ * al widget GtkList
+ */
+static void sigh_print_selection (GtkWidget *gtklist,
+ gpointer func_data);
+static void sigh_button_event (GtkWidget *gtklist,
+ GdkEventButton *event,
+ GtkWidget *frame);
+
+
+/* funzione main per predisporre l'interfaccia utente */
+
+gint main (int argc, gchar *argv[])
+{
+ GtkWidget *separator;
+ GtkWidget *window;
+ GtkWidget *vbox;
+ GtkWidget *scrolled_window;
+ GtkWidget *frame;
+ GtkWidget *gtklist;
+ GtkWidget *button;
+ GtkWidget *list_item;
+ GList *dlist;
+ guint i;
+ gchar buffer[64];
+
+
+ /* inizializza gtk+ (e di conseguenza gdk) */
+
+ gtk_init(&amp;argc, &amp;argv);
+
+
+ /* crea una finestra in cui mettere tutti i widget
+ * connette gtk_main_quit() al segnale "destroy" della finestra
+ * per gestire le richieste di chiusura finestra del window manager
+ */
+ window=gtk_window_new(GTK_WINDOW_TOPLEVEL);
+ gtk_window_set_title(GTK_WINDOW(window), "GtkList Example");
+ gtk_signal_connect(GTK_OBJECT(window),
+ "destroy",
+ GTK_SIGNAL_FUNC(gtk_main_quit),
+ NULL);
+
+
+ /* all'interno della finestra abbiamo bisogno di una scatola
+ * in cui mettere i widget verticalmente */
+ vbox=gtk_vbox_new(FALSE, 5);
+ gtk_container_border_width(GTK_CONTAINER(vbox), 5);
+ gtk_container_add(GTK_CONTAINER(window), vbox);
+ gtk_widget_show(vbox);
+
+ /* questa &egrave; la finestra scorribile in cui mettere il widget GtkList */
+ scrolled_window=gtk_scrolled_window_new(NULL, NULL);
+ gtk_widget_set_usize(scrolled_window, 250, 150);
+ gtk_container_add(GTK_CONTAINER(vbox), scrolled_window);
+ gtk_widget_show(scrolled_window);
+
+ /* crea il widget GtkList
+ * connette il gestore di segnale sigh_print_selection()
+ * al segnale "selection_changed" della GtkList, per stampare
+ * gli elementi selezionati ogni volta che la selezione cambia
+ */
+ gtklist=gtk_list_new();
+ gtk_container_add(GTK_CONTAINER(scrolled_window), gtklist);
+ gtk_widget_show(gtklist);
+ gtk_signal_connect(GTK_OBJECT(gtklist),
+ "selection_changed",
+ GTK_SIGNAL_FUNC(sigh_print_selection),
+ NULL);
+
+ /* creiamo una "Prigione" (Prison) in cui mettere gli elementi di lista ;)
+ */
+ frame=gtk_frame_new("Prison");
+ gtk_widget_set_usize(frame, 200, 50);
+ gtk_container_border_width(GTK_CONTAINER(frame), 5);
+ gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_OUT);
+ gtk_container_add(GTK_CONTAINER(vbox), frame);
+ gtk_widget_show(frame);
+
+ /* connette il gestore di segnale sigh_button_event() alla GtkList
+ * il quale gestira' l'"imprigionamento" degli elementi di lista
+ */
+ gtk_signal_connect(GTK_OBJECT(gtklist),
+ "button_release_event",
+ GTK_SIGNAL_FUNC(sigh_button_event),
+ frame);
+
+ /* crea un separatore
+ */
+ separator=gtk_hseparator_new();
+ gtk_container_add(GTK_CONTAINER(vbox), separator);
+ gtk_widget_show(separator);
+
+ /* infine creiamo un bottone e connettiamone il segnale "clicked"
+ * alla distruzione della finestra
+ */
+ button=gtk_button_new_with_label("Close");
+ gtk_container_add(GTK_CONTAINER(vbox), button);
+ gtk_widget_show(button);
+ gtk_signal_connect_object(GTK_OBJECT(button),
+ "clicked",
+ GTK_SIGNAL_FUNC(gtk_widget_destroy),
+ GTK_OBJECT(window));
+
+
+ /* a questo punto creiamo 5 elementi di lista, ognuno con la
+ * propria etichetta, e li aggiungiamo alla GtkList usando
+ * gtk_container_add(). Inoltre, recuperiamo la stringa di testo
+ * dall'etichetta e la associamo, per ogni elemento, a
+ * list_item_data_key
+ */
+ for (i=0; i<5; i++) {
+ GtkWidget *label;
+ gchar *string;
+
+ sprintf(buffer, "ListItemContainer with Label #%d", i);
+ label=gtk_label_new(buffer);
+ list_item=gtk_list_item_new();
+ gtk_container_add(GTK_CONTAINER(list_item), label);
+ gtk_widget_show(label);
+ gtk_container_add(GTK_CONTAINER(gtklist), list_item);
+ gtk_widget_show(list_item);
+ gtk_label_get(GTK_LABEL(label), &amp;string);
+ gtk_object_set_data(GTK_OBJECT(list_item),
+ list_item_data_key,
+ string);
+ }
+
+ /* qui creiamo altre 5 etichette, questa volta usando
+ * per la creazione gtk_list_item_new_with_label().
+ * Non possiamo recuperare la stringa di testo dall'etichetta
+ * dal momento che non disponiamo di puntatori alle etichette,
+ * quindi associamo semplicemente il list_item_data_key di ogni
+ * elemento di lista con la medesima stringa di testo.
+ * Per aggiungere elementi di lista, li mettiamo tutti in una lista
+ * doppiamente collegata (GList), e quindi li aggiungiamo con una
+ * unica chiamata a gtk_list_append_items().
+ * Dal momento che usiamo g_list_prepend() per mettere gli elementi
+ * nella lista doppiamente collegata, il loro ordine sara' discendente
+ * (invece che ascendente come sarebbe se usassimo g_list_append())
+ */
+ dlist=NULL;
+ for (; i<10; i++) {
+ sprintf(buffer, "List Item with Label %d", i);
+ list_item=gtk_list_item_new_with_label(buffer);
+ dlist=g_list_prepend(dlist, list_item);
+ gtk_widget_show(list_item);
+ gtk_object_set_data(GTK_OBJECT(list_item),
+ list_item_data_key,
+ "ListItem with integrated Label");
+ }
+ gtk_list_append_items(GTK_LIST(gtklist), dlist);
+
+ /* e finalmente vogliamo vedere la finestra, non e' vero? ;)
+ */
+ gtk_widget_show(window);
+
+ /* lancia il ciclo principale di gtk
+ */
+ gtk_main();
+
+ /* si arriva a questo punto dopo la chiamata di gtk_main_quit(),
+ * il che accade quando viene distrutta la finestra principale
+ */
+ return 0;
+}
+
+/* questo e' il gestore di segnale che e' stato connesso all'evento di
+ * pressione/rilascio del bottone della GtkList
+ */
+void
+sigh_button_event (GtkWidget *gtklist,
+ GdkEventButton *event,
+ GtkWidget *frame)
+{
+ /* facciamo qualcosa solo nel caso di rilascio del terzo bottone
+ * (quello piu' a destra)
+ */
+ if (event->type==GDK_BUTTON_RELEASE &amp;&amp;
+ event->button==3) {
+ GList *dlist, *free_list;
+ GtkWidget *new_prisoner;
+
+ /* recuperiamo l'elemento di lista selezionato correntemente,
+ * che sara' il nostro prossimo prigioniero ;)
+ */
+ dlist=GTK_LIST(gtklist)->selection;
+ if (dlist)
+ new_prisoner=GTK_WIDGET(dlist->data);
+ else
+ new_prisoner=NULL;
+
+ /* cerchiamo elementi di lista gia' imprigionati,
+ * li rimetteremo nella lista.
+ * Ricordare di liberare la lista doppiamente collegata
+ * che viene restituita da gtk_container_children()
+ */
+ dlist=gtk_container_children(GTK_CONTAINER(frame));
+ free_list=dlist;
+ while (dlist) {
+ GtkWidget *list_item;
+
+ list_item=dlist->data;
+
+ gtk_widget_reparent(list_item, gtklist);
+
+ dlist=dlist->next;
+ }
+ g_list_free(free_list);
+
+ /* se abbiamo un nuovo prigioniero, lo rimuoviamo
+ * dalla GtkList e lo mettiamo nella cornice della
+ * "Prigione". Dobbiamo prima deselezionare l'elemento
+ */
+ if (new_prisoner) {
+ GList static_dlist;
+
+ static_dlist.data=new_prisoner;
+ static_dlist.next=NULL;
+ static_dlist.prev=NULL;
+
+ gtk_list_unselect_child(GTK_LIST(gtklist),
+ new_prisoner);
+ gtk_widget_reparent(new_prisoner, frame);
+ }
+ }
+}
+
+/* questo e' il gestore di segnaleche viene chiamato de la
+ * GtkList emette il segnale "selection_changed"
+ */
+void
+sigh_print_selection (GtkWidget *gtklist,
+ gpointer func_data)
+{
+ GList *dlist;
+
+ /* recuperiamo la lista doppiamente collegata degli
+ * elementi selezionati della GtkList, ricordate di
+ * trattarla come sola lettura
+ */
+ dlist=GTK_LIST(gtklist)->selection;
+
+ /* se non ci sono elementi selezionati non c'e' altro da
+ * fare che dirlo all'utente
+ */
+ if (!dlist) {
+ g_print("Selection cleared\n");
+ return;
+ }
+ /* ok, abbiamo una selezione e quindi lo scriviamo
+ */
+ g_print("The selection is a ");
+
+ /* ottieniamo l'elemento di lista dalla lista doppiamente
+ * collegata e poi richiediamo i dati associati con
+ * list_item_data_key. Poi semplicemente li stampiamo
+ */
+ while (dlist) {
+ GtkObject *list_item;
+ gchar *item_data_string;
+
+ list_item=GTK_OBJECT(dlist->data);
+ item_data_string=gtk_object_get_data(list_item,
+ list_item_data_key);
+ g_print("%s ", item_data_string);
+
+ dlist=dlist->next;
+ }
+ g_print("\n");
+}
+</verb></tscreen>
+
+<sect1> Il Widget Elemento di Lista (List Item)
+<p>
+Il widget GtkListItem &egrave; progettato allo scopo di essere un contenitore
+collegato ad un figlio, per fornire le funzioni per la selezione e deselezione
+allo stesso modo in cui il widget GtkList ne ha bisogno per i propri figli.
+
+Un GtkListItem ha la sua propria finestra per ricevere eventi, e ha il suo
+proprio colore di sfondo, che di solito &egrave; bianco.
+
+Dal momento che questo widget deriva direttamente da GtkItem, pu&ograve; essere
+trattato come tale usando la macro GTK_ITEM(ListItem), vedere il widget
+GtkItem per ulteriori informazioni.
+Di solito un GtkListItem ha solo un'etichetta per identificare per esempio
+un nome di file all'interno di una GtkList -- per cui viene fornita la
+funzione appropriata gtk_list_item_new_with_label(). Si pu&ograve; ottenere lo
+stesso effetto creando una GtkLabel da sola, assegnando al suo allineamento
+i valori xalign=0 e yalign=0.5, aggiungendo successivamente un contenitore
+alla GtkListItem.
+
+Dal momento che non si &egrave; obbligati a mettere una GtkLabel, si pu&ograve; anche
+aggiungere una GtkVBox una GtkArrow ecc. alla GtkListItem.
+
+<sect1> Segnali
+<p>
+Un GtkListItem non crea alcun nuovo segnale di per se, ma eredita
+i segnali di GtkItem. Per ulteriori informazioni, vedere GtkItem::.
+
+
+<sect1> Funzioni
+<p>
+
+<tscreen><verb>
+guint gtk_list_item_get_type (void)
+</verb></tscreen>
+
+Restituisce l'identificatore di tipo `GtkListItem'.
+
+<tscreen><verb>
+GtkWidget* gtk_list_item_new (void)
+</verb></tscreen>
+
+Crea un nuovo oggetto `GtkListItem'. Il nuovo widget viene restituito
+sottoforma di un puntatore ad un oggetto `GtkWidget'. In caso di
+fallimento, viene restituito `NULL'.
+
+<tscreen><verb>
+GtkWidget* gtk_list_item_new_with_label (gchar *LABEL)
+</verb></tscreen>
+
+Cre un nuovo oggetto `GtkListItem', avente come unico figlio
+un GtkLabel. Il nuovo widget viene restituito
+sottoforma di un puntatore ad un oggetto `GtkWidget'. In caso di
+fallimento, viene restituito `NULL'.
+
+<tscreen><verb>
+void gtk_list_item_select (GtkListItem *LIST_ITEM)
+</verb></tscreen>
+
+Questa funzione &egrave; essenzialmente un wrapper per una chiamata a
+gtk_item_select (GTK_ITEM (list_item)) che emetter&agrave; il segnale
+GtkItem::select.
+Vedere GtkItem:: per maggiori informazioni.
+
+<tscreen><verb>
+void gtk_list_item_deselect (GtkListItem *LIST_ITEM)
+</verb></tscreen>
+
+Questa funzione &egrave; essenzialmente un wrapper per una chiamata a
+gtk_item_deselect (GTK_ITEM (list_item)) che emetter&agrave; il segnale
+GtkItem::deselect.
+Vedere GtkItem:: per maggiori informazioni.
+
+<tscreen><verb>
+GtkListItem* GTK_LIST_ITEM (gpointer OBJ)
+</verb></tscreen>
+
+Effettua il cast di un puntatore generico a `GtkListItem*'. Vedere
+Standard Macros:: per maggiorni informazioni.
+
+<tscreen><verb>
+GtkListItemClass* GTK_LIST_ITEM_CLASS (gpointer CLASS)
+</verb></tscreen>
+
+Effettua il cast di un puntatore generico a `GtkListItemClass*'. Vedere
+Standard Macros:: per maggiorni informazioni.
+
+<tscreen><verb>
+gint GTK_IS_LIST_ITEM (gpointer OBJ)
+</verb></tscreen>
+
+Determina se un puntatore generico si riferisce ad un oggetto
+`GtkListItem'. Vedere Standard Macros:: per maggiorni informazioni.
+
+<sect1> Esempio
+<p>
+Come esempio su questo argomento, si veda quello relativo alla GtkList,
+che riguarda anche l'uso del GtkListItem.
+
+<sect> Selezione di File (File Selections)
+<p>
+
+Il widget Selezione di File &egrave; un modo rapido e semplice per mostrare una
+finestra di dialogo `File'. Questa si presenta completa di bottoni Ok,
+Cancel e Help, un buon modo per tagliare i tempi di programmazione.
+
+Per creare una nuova finestra di selezione file usate:
+
+<tscreen><verb>
+GtkWidget* gtk_file_selection_new (gchar *title);
+</verb></tscreen>
+
+Per assegnare il nome del file, ad esempio per predisporre una certa
+directory o per dare un certo nome di file per difetto, usate la seguente
+funzione:
+
+<tscreen><verb>
+void gtk_file_selection_set_filename (GtkFileSelection *filesel, gchar *filename);
+</verb></tscreen>
+
+Per recuperare il testo che l'utente ha inserito o che ha selezionato con
+il mouse, si usa la funzione:
+
+<tscreen><verb>
+gchar* gtk_file_selection_get_filename (GtkFileSelection *filesel);
+</verb></tscreen>
+
+Ci sono anche dei puntatori ai widget che sono contenuti all'interno
+del widget di selezione file. Si tratta di:
+
+<itemize>
+<item>dir_list
+<item>file_list
+<item>selection_entry
+<item>selection_text
+<item>main_vbox
+<item>ok_button
+<item>cancel_button
+<item>help_button
+</itemize>
+
+Molto probabilmente potreste voler usare i puntatori a ok_button,
+cancel_button e help_button per segnalarne l'uso.
+
+Ecco un esempio rubato da testgtk.c, nodificato per essere eseguito da
+solo. Come potrete vedere, non c'&egrave; molto pi&ugrave; che la creazione di un
+widget di selezione file. In questo esempio, il bottone Help non fa nulla
+mentre &egrave; mostrato allo schermo, dal momento che non c'&egrave; alcun segnale
+collegato con esso.
+
+<tscreen><verb>
+#include <gtk/gtk.h>
+
+/* Recupera il nome di file selezionato e stampalo a console */
+void file_ok_sel (GtkWidget *w, GtkFileSelection *fs)
+{
+ g_print ("%s\n", gtk_file_selection_get_filename (GTK_FILE_SELECTION (fs)));
+}
+
+void destroy (GtkWidget *widget, gpointer *data)
+{
+ gtk_main_quit ();
+}
+
+int main (int argc, char *argv[])
+{
+ GtkWidget *filew;
+
+ gtk_init (&amp;argc, &amp;argv);
+
+ /* Crea un nuovo widget di selezione file */
+ filew = gtk_file_selection_new ("File selection");
+
+ gtk_signal_connect (GTK_OBJECT (filew), "destroy",
+ (GtkSignalFunc) destroy, &amp;filew);
+ /* Connette ok_button alla funzione file_ok_sel */
+ gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (filew)->ok_button),
+ "clicked", (GtkSignalFunc) file_ok_sel, filew );
+
+ /* Connette cancel_button alla funzione di distruzione del widget */
+ gtk_signal_connect_object (GTK_OBJECT (GTK_FILE_SELECTION (filew)->cancel_button),
+ "clicked", (GtkSignalFunc) gtk_widget_destroy,
+ GTK_OBJECT (filew));
+
+ /* Preassegnamo un nome di file, come se stessimo dando un valore per difetto in
+ dialogo di tipo `` salva con nome '' */
+ gtk_file_selection_set_filename (GTK_FILE_SELECTION(filew),
+ "penguin.png");
+
+ gtk_widget_show(filew);
+ gtk_main ();
+ return 0;
+}
+</verb></tscreen>
+
+<sect>Il Widget Men&ugrave; (Menu Widgets)
+<p>
+Ci sono due modi per creare dei men&ugrave;, quello facile e quello difficile.
+Ognuno &egrave; pi&ugrave; adatto per certe circostanze, ma di solito si pu&ograve; usare il
+modo semplice, cio&eacute; menu_factory (la ``fabbrica dei men&ugrave;''). Il modo
+``difficile'' &egrave; di crearsi tutti i men&ugrave; usando direttamente le chiamate.
+Quello semplice &egrave; di usare le chiamate di tipo gtk_menu_factory. Anche se
+&egrave; un modo molto pi&ugrave; semplice, ci sono svantaggi e vantaggi per ciascuno
+dei due approcci.
+
+La menufactory &egrave; molto pi&ugrave; semplice da usare e per aggiungere dei nuovi
+men&ugrave;, anche se scriversi un po' di funzioni per creare dei men&ugrave; con il
+metodo manuale pu&ograve; dare risultati molto migliori dal punto di vista
+dell'usabilit&agrave;. Con la menufactory, non &egrave; possibile mettere immagini o
+segni '/' nei men&ugrave;.
+<p>
+<sect1>Creazione Manuale di Men&ugrave;
+<p>
+Seguendo la tradizionale arte dell'insegnamento, partiamo dal modo
+difficile. <tt>:)</>
+<p>
+Diamo un'occhiata alle funzioni usate per creare dei men&ugrave;.
+Con questa prima funzione si crea un nuovo men&ugrave;:
+
+<tscreen><verb>
+GtkWidget *gtk_menu_bar_new()
+</verb></tscreen>
+
+Questa funzione crea una nuova barra di men&ugrave;. Per impacchettarla in una
+finestra o si usa la funzione gtk_container_add, oppure, per impacchettarla
+in una scatola, le funzioni box_pack - come con i bottoni.
+
+<tscreen><verb>
+GtkWidget *gtk_menu_new();
+</verb></tscreen>
+
+Questa funzione restituisce un puntatore ad un nuovo men&ugrave;, non viene mai
+realmente mostrato (con gtk_widget_show), serve solo per contenere gli
+elementi del men&ugrave;. Spero che il tutto risulti pi&ugrave; chiaro quando dare
+un'occhiata all'esempio pi&ugrave; sotto.
+<p>
+Le prossime due chiamate sono usate per creare degli elementi che poi
+vengono impacchettati nel men&ugrave;.
+
+<tscreen><verb>
+GtkWidget *gtk_menu_item_new()
+</verb></tscreen>
+
+e
+
+<tscreen><verb>
+GtkWidget *gtk_menu_item_new_with_label(const char *label)
+</verb></tscreen>
+
+Queste chiamate sono usate per creare i menu che devono essere mostrati.
+Ricordate la differenza che esiste fra un ``men&ugrave;'' come quelli creati con
+gtk_menu_new e un ``elemento di men&ugrave;'' (menu item) come quelli creati con
+la funzione creata con gtk_menu_item_new. L'elemento di men&ugrave; sar&agrave; un bottone
+vero e proprio con una azione associata, mentre un men&ugrave; &egrave; solo un contenitore
+che li raccoglie.
+
+<tscreen><verb>
+gtk_menu_item_append()
+
+gtk_menu_item_set_submenu()
+</verb></tscreen>
+
+Le funzioni gtk_menu_item_new_with_label e gtk_menu_item_new si comportano esattamente come
+vi aspettereste dopo aver visto le funzioni che riguardano i bottoni. La prima
+crea un elemento di men&ugrave; con un'etichetta gi&agrave; applicata, mentre la seconda crea
+un nuovo elemento di men&ugrave; vuoto.
+<p>
+Ecco i passi necessari per creare una barra di men&ugrave; con i relativi men&ugrave; collegati:
+<itemize>
+<item> Create un nuovo men&ugrave; con gtk_menu_new()
+<item> Create un elementoa di men&ugrave; con using gtk_menu_item_new(). Questo rappresenta
+ la base del men&ugrave;, e il testo che appare qui sar&agrave; sulla barra stessa.
+<item> Usate delle chiamate multiple a gtk_menu_item_new() per ognuno degli
+ elementi che volete mettere nel vostro men&ugrave;. Usate inoltre gtk_menu_item_append()
+ per mettere assieme ognuno di questi nuovo elementi. Si crea cos&igrave; una lista di
+ elementi di men&ugrave;.
+<item> Usate gtk_menu_item_set_submenu() per attaccare gli elementi di men&ugrave;
+ creati all'elemento di men&ugrave; base (quello creato nel secondo passaggio).
+<item> Create una nuova barra di men&ugrave; usando gtk_menu_bar_new. Questo passo
+ necessita di essere effettuato una sola volta quando si crea una serie di
+ men&ugrave; su una serie di men&ugrave; su una sola barra.
+<item> Usate gtk_menu_bar_append per mettere il men&ugrave; base sulla barra dei men&ugrave;.
+</itemize>
+<p>
+Creare un men&ugrave; a comparsa &egrave; pi&ugrave; o meno la stessa cosa. La differenza &egrave; che il
+il men&ugrave; non viene attivato ``automaticamente'' da una barra, bens&igrave; esplicitamente
+con la chiamata alla funzione gtk_menu_popup() da un evento di pressione di
+un pulsante.
+Seguite questi passaggi:
+<itemize>
+<item>Create una funzione di gestione di un evento. Essa deve seguire il prototipo
+<tscreen>
+static gint handler(GtkWidget *widget, GdkEvent *event);
+</tscreen>
+e usare l'evento per scoprire dove il menu deve essere fatto comparire.
+<item>Nel gestore di evento, se questo &egrave; la pressione di un bottone, trattate
+<tt>event</tt> come l'evento relativo ad un bottone (cosa che in effetti &egrave;)
+e usatelo come mostrato nel codice di esempio per passare informazioni a
+gtk_menu_popup().
+<item>Collegate il gestore di evento a un widget con
+<tscreen>
+gtk_signal_connect_object(GTK_OBJECT(widget), "event",
+ GTK_SIGNAL_FUNC (handler), GTK_OBJECT(menu));
+</tscreen>
+in cui <tt>widget</tt> &egrave; il widget a cui state effettuando il collegamento, e
+<tt>handler</tt> &egrave; la funzione di gestione, mentre <tt>menu</tt> &egrave; un men&ugrave;
+creato con gtk_menu_new(). Quest'ultimo pu&ograve; essere un men&ugrave; che viene anche
+attivato da una barra di men&ugrave;, come mostrato nel codice di esempio.
+</itemize>
+<p>
+<sect1>Esempio di Men&ugrave; Manuale
+<p>
+Per la teoria dovrebbe essere abbastanza. Diamo un'occhiata ad un esempio che
+ci aiuti a chiarire le cose.
+
+<tscreen><verb>
+
+#include <gtk/gtk.h>
+
+static gint button_press (GtkWidget *, GdkEvent *);
+static void menuitem_response (gchar *);
+
+
+int main (int argc, char *argv[])
+{
+
+ GtkWidget *window;
+ GtkWidget *menu;
+ GtkWidget *menu_bar;
+ GtkWidget *root_menu;
+ GtkWidget *menu_items;
+ GtkWidget *vbox;
+ GtkWidget *button;
+ char buf[128];
+ int i;
+
+ gtk_init (&amp;argc, &amp;argv);
+
+ /* crea una nuova finestra */
+ window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+ gtk_window_set_title(GTK_WINDOW (window), "GTK Menu Test");
+ gtk_signal_connect(GTK_OBJECT (window), "delete_event",
+ (GtkSignalFunc) gtk_exit, NULL);
+
+ /* Inizializziamo il men&ugrave;, e ricordate: mai applicare
+ * gtk_show_widget() al widget men&ugrave;!!
+ * Questo &egrave; il men&ugrave; che contiene gli elementi, quello che
+ * spunta quando si fa click sul "Men&ugrave; radice" nell'applicazione */
+ menu = gtk_menu_new();
+
+ /* Questo &egrave; il men&ugrave; radice, e l'etichetta sar&agrave; il nome del men&ugrave; che
+ * verr&agrave; mostrato sulla barra dei men&ugrave;. Non ci sar&agrave; alcun gestore di
+ * segnale collegato, dal momento che non fa altro che mostrare il resto
+ * del men&ugrave; quando viene premuto. */
+ root_menu = gtk_menu_item_new_with_label("Root Menu");
+
+ gtk_widget_show(root_menu);
+
+ /* Ora creiamo un ciclo che crea tre elementi di menu per "test-menu".
+ * Notete la chiamata a gtk_menu_append. In questo punto aggiungiamo una
+ * lista di elementi al nostro men&ugrave;. Normalmente, dovremmo poi catturare
+ * il segnale di attivazione per ognuno degli elementi del menu, e creare
+ * una funzione di ritorno per ciascuno di essi, ma qui non li mettiamo per
+ * brevit&agrave;. */
+
+ for(i = 0; i < 3; i++)
+ {
+ /* Copia i nomi in buf. */
+ sprintf(buf, "Test-undermenu - %d", i);
+
+ /* Crea un nuovo elemento di men&ugrave; con un nome... */
+ menu_items = gtk_menu_item_new_with_label(buf);
+
+ /* ...e aggiungilo al men&ugrave;. */
+ gtk_menu_append(GTK_MENU (menu), menu_items);
+
+ /* Fa qualcosa di interessante quando si seleziona l'elemento */
+ gtk_signal_connect_object(GTK_OBJECT(menu_items), "activate",
+ GTK_SIGNAL_FUNC(menuitem_response), (gpointer) g_strdup(buf));
+
+ /* Mostra il widget */
+ gtk_widget_show(menu_items);
+ }
+
+ /* Ora specifichiamo che vogliamo che il men&ugrave; che abbiamo appena creato
+ * sia il men&ugrave; radice *//
+ gtk_menu_item_set_submenu(GTK_MENU_ITEM (root_menu), menu);
+
+ /* Una vbox in cui mettere un men&ugrave; ed un bottone: */
+ vbox = gtk_vbox_new(FALSE, 0);
+ gtk_container_add(GTK_CONTAINER(window), vbox);
+ gtk_widget_show(vbox);
+
+ /* Crea una barra dei men&ugrave; per metterci i men&ugrave; e l'aggiunge alla finestra principale */
+ menu_bar = gtk_menu_bar_new();
+ gtk_box_pack_start(GTK_BOX(vbox), menu_bar, FALSE, FALSE, 2);
+ gtk_widget_show(menu_bar);
+
+ /* Crea un bottone a cui collegare un men&ugrave; */
+ button = gtk_button_new_with_label("press me");
+ gtk_signal_connect_object(GTK_OBJECT(button), "event",
+ GTK_SIGNAL_FUNC (button_press), GTK_OBJECT(menu));
+ gtk_box_pack_end(GTK_BOX(vbox), button, TRUE, TRUE, 2);
+ gtk_widget_show(button);
+
+ /* E finalmente attacchiamo l'elemento di men&ugrave; alla barra dei men&ugrave; -- questo
+ * &egrave; l'elemento di men&ugrave; "radice" di cui parlavo */
+ gtk_menu_bar_append(GTK_MENU_BAR (menu_bar), root_menu);
+
+ /* La finestra va mostrata sempre come ultimo passo in modo che sia gi&agrave;
+ * completa di tutti i suoi elementi. */
+ gtk_widget_show(window);
+
+ gtk_main ();
+
+ return 0;
+}
+
+
+
+/* Risponde alla pressione di un bottone impostando un men&ugrave; che
+ * viene passato come widget.
+ * Notate che l'argomento "widget" si riferisce al men&ugrave; impostato
+ * e NON al bottone premuto.
+ */
+
+static gint button_press (GtkWidget *widget, GdkEvent *event)
+{
+
+ if (event->type == GDK_BUTTON_PRESS) {
+ GdkEventButton *bevent = (GdkEventButton *) event;
+ gtk_menu_popup (GTK_MENU(widget), NULL, NULL, NULL, NULL,
+ bevent->button, bevent->time);
+ /* Riferisce al codice chiamante che abbiamo trattato l'evento;
+ * la faccenda finisce qui. */
+ return TRUE;
+ }
+
+ /* Riferisce al codice chiamante che abbiamo trattato l'evento; passa avanti. */
+ return FALSE;
+}
+
+
+/* Stampa una stringa quando viene selezionato un elemento di men&ugrave; */
+
+static void menuitem_response (gchar *string)
+{
+ printf("%s\n", string);
+}
+</verb></tscreen>
+
+Si pu&ograve; anche fare in modo che un elemento di men&ugrave; sia insensibile e, usando
+una tabella di acelleratori, collegare dei tasti a delle funzioni di men&ugrave;.
+<p>
+<sect1>Usare GtkMenuFactory
+<p>
+Ora che vi abbiamo mostrato il modo difficile, ecco invece come si fa usando
+le chiamate di gtk_menu_factory.
+<p>
+<sect1>Esempio di Menu Factory
+<p>
+Ecco un esempio di utilizzo della ``Fabbrica'' di Men&ugrave; di GTK (Menu Factory).
+Questo &egrave; il primo file, menus.h. Teniemo dei file menus.c e main.c separati
+a causa delle variabili globali usate nel file menus.c.
+
+<tscreen><verb>
+#ifndef __MENUS_H__
+#define __MENUS_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+void get_main_menu (GtkWidget **menubar, GtkAcceleratorTable **table);
+void menus_create(GtkMenuEntry *entries, int nmenu_entries);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __MENUS_H__ */
+</verb></tscreen>
+<p>
+Ed ecco il file menus.c.
+
+<tscreen><verb>
+
+#include <gtk/gtk.h>
+#include <strings.h>
+
+#include "main.h"
+
+
+static void menus_remove_accel(GtkWidget * widget, gchar * signal_name, gchar * path);
+static gint menus_install_accel(GtkWidget * widget, gchar * signal_name, gchar key, gchar modifiers, gchar * path);
+void menus_init(void);
+void menus_create(GtkMenuEntry * entries, int nmenu_entries);
+
+/* Questa &egrave; la struttuta GtkMenuEntry, che viene usata per creare dei nuovi
+ * men&ugrave;. Il primo membro &agrave; la stringa di definizione del men&ugrave;. Il secondo
+ * &egrave; il tasto acceleratore predefinito, usato per accedere a questa funzione
+ * con la tastiera. Il terzo &egrave; la funzione di ritorno che viene chiamata
+ * quando si seleziona con la tastiera o il mouse questo elemento di men&ugrave;.
+ * L'ultimo membro costituisce il dato che viene passato alla funzione di
+ * ritorno. */
+
+static GtkMenuEntry menu_items[] =
+{
+ {"<Main>/File/New", "<control>N", NULL, NULL},
+ {"<Main>/File/Open", "<control>O", NULL, NULL},
+ {"<Main>/File/Save", "<control>S", NULL, NULL},
+ {"<Main>/File/Save as", NULL, NULL, NULL},
+ {"<Main>/File/<separator>", NULL, NULL, NULL},
+ {"<Main>/File/Quit", "<control>Q", file_quit_cmd_callback, "OK, I'll quit"},
+ {"<Main>/Options/Test", NULL, NULL, NULL}
+};
+
+/* calculail numero di menu_item */
+static int nmenu_items = sizeof(menu_items) / sizeof(menu_items[0]);
+
+static int initialize = TRUE;
+static GtkMenuFactory *factory = NULL;
+static GtkMenuFactory *subfactory[1];
+static GHashTable *entry_ht = NULL;
+
+void get_main_menu(GtkWidget ** menubar, GtkAcceleratorTable ** table)
+{
+ if (initialize)
+ menus_init();
+
+ if (menubar)
+ *menubar = subfactory[0]->widget;
+ if (table)
+ *table = subfactory[0]->table;
+}
+
+void menus_init(void)
+{
+ if (initialize) {
+ initialize = FALSE;
+
+ factory = gtk_menu_factory_new(GTK_MENU_FACTORY_MENU_BAR);
+ subfactory[0] = gtk_menu_factory_new(GTK_MENU_FACTORY_MENU_BAR);
+
+ gtk_menu_factory_add_subfactory(factory, subfactory[0], "<Main>");
+ menus_create(menu_items, nmenu_items);
+ }
+}
+
+void menus_create(GtkMenuEntry * entries, int nmenu_entries)
+{
+ char *accelerator;
+ int i;
+
+ if (initialize)
+ menus_init();
+
+ if (entry_ht)
+ for (i = 0; i < nmenu_entries; i++) {
+ accelerator = g_hash_table_lookup(entry_ht, entries[i].path);
+ if (accelerator) {
+ if (accelerator[0] == '\0')
+ entries[i].accelerator = NULL;
+ else
+ entries[i].accelerator = accelerator;
+ }
+ }
+ gtk_menu_factory_add_entries(factory, entries, nmenu_entries);
+
+ for (i = 0; i < nmenu_entries; i++)
+ if (entries[i].widget) {
+ gtk_signal_connect(GTK_OBJECT(entries[i].widget), "install_accelerator",
+ (GtkSignalFunc) menus_install_accel,
+ entries[i].path);
+ gtk_signal_connect(GTK_OBJECT(entries[i].widget), "remove_accelerator",
+ (GtkSignalFunc) menus_remove_accel,
+ entries[i].path);
+ }
+}
+
+static gint menus_install_accel(GtkWidget * widget, gchar * signal_name, gchar key, gchar modifiers, gchar * path)
+{
+ char accel[64];
+ char *t1, t2[2];
+
+ accel[0] = '\0';
+ if (modifiers & GDK_CONTROL_MASK)
+ strcat(accel, "<control>");
+ if (modifiers & GDK_SHIFT_MASK)
+ strcat(accel, "<shift>");
+ if (modifiers & GDK_MOD1_MASK)
+ strcat(accel, "<alt>");
+
+ t2[0] = key;
+ t2[1] = '\0';
+ strcat(accel, t2);
+
+ if (entry_ht) {
+ t1 = g_hash_table_lookup(entry_ht, path);
+ g_free(t1);
+ } else
+ entry_ht = g_hash_table_new(g_string_hash, g_string_equal);
+
+ g_hash_table_insert(entry_ht, path, g_strdup(accel));
+
+ return TRUE;
+}
+
+static void menus_remove_accel(GtkWidget * widget, gchar * signal_name, gchar * path)
+{
+ char *t;
+
+ if (entry_ht) {
+ t = g_hash_table_lookup(entry_ht, path);
+ g_free(t);
+
+ g_hash_table_insert(entry_ht, path, g_strdup(""));
+ }
+}
+
+void menus_set_sensitive(char *path, int sensitive)
+{
+ GtkMenuPath *menu_path;
+
+ if (initialize)
+ menus_init();
+
+ menu_path = gtk_menu_factory_find(factory, path);
+ if (menu_path)
+ gtk_widget_set_sensitive(menu_path->widget, sensitive);
+ else
+ g_warning("Impossibile assegnare sensibilit&agrave; a men&ugrave; inesistente: %s", path);
+}
+
+</verb></tscreen>
+<p>
+Ed ecco main.h
+
+<tscreen><verb>
+#ifndef __MAIN_H__
+#define __MAIN_H__
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+void file_quit_cmd_callback(GtkWidget *widget, gpointer data);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __MAIN_H__ */
+
+</verb></tscreen>
+<p>
+E main.c
+
+<tscreen><verb>
+#include <gtk/gtk.h>
+
+#include "main.h"
+#include "menus.h"
+
+
+int main(int argc, char *argv[])
+{
+ GtkWidget *window;
+ GtkWidget *main_vbox;
+ GtkWidget *menubar;
+
+ GtkAcceleratorTable *accel;
+
+ gtk_init(&amp;argc, &amp;argv);
+
+ window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+ gtk_signal_connect(GTK_OBJECT(window), "destroy",
+ GTK_SIGNAL_FUNC(file_quit_cmd_callback),
+ "WM destroy");
+ gtk_window_set_title(GTK_WINDOW(window), "Menu Factory");
+ gtk_widget_set_usize(GTK_WIDGET(window), 300, 200);
+
+ main_vbox = gtk_vbox_new(FALSE, 1);
+ gtk_container_border_width(GTK_CONTAINER(main_vbox), 1);
+ gtk_container_add(GTK_CONTAINER(window), main_vbox);
+ gtk_widget_show(main_vbox);
+
+ get_main_menu(&amp;menubar, &amp;accel);
+ gtk_window_add_accelerator_table(GTK_WINDOW(window), accel);
+ gtk_box_pack_start(GTK_BOX(main_vbox), menubar, FALSE, TRUE, 0);
+ gtk_widget_show(menubar);
+
+ gtk_widget_show(window);
+ gtk_main();
+
+ return(0);
+}
+
+/* Questo &egrave; per mostrare come si usano le funzioni di ritorno quando
+ * si utilizza la MenuFactory. Spesso, si mettono tutte le funzioni di
+ * callback in un file separato, e le si fanno chiamare le funzioni
+ * appropriate da l&igrave;. Cos&igrave; le cose sono pi&ugrave; organizzate. */
+void file_quit_cmd_callback (GtkWidget *widget, gpointer data)
+{
+ g_print ("%s\n", (char *) data);
+ gtk_exit(0);
+}
+</verb></tscreen>
+<p>
+Ed infine un bel makefile per semplificare la compilazione.
+
+<tscreen><verb>
+CC = gcc
+PROF = -g
+C_FLAGS = -Wall $(PROF) -L/usr/local/include -DDEBUG
+L_FLAGS = $(PROF) -L/usr/X11R6/lib -L/usr/local/lib
+L_POSTFLAGS = -lgtk -lgdk -lglib -lXext -lX11 -lm
+PROGNAME = at
+
+O_FILES = menus.o main.o
+
+$(PROGNAME): $(O_FILES)
+ rm -f $(PROGNAME)
+ $(CC) $(L_FLAGS) -o $(PROGNAME) $(O_FILES) $(L_POSTFLAGS)
+
+.c.o:
+ $(CC) -c $(C_FLAGS) $<
+
+clean:
+ rm -f core *.o $(PROGNAME) nohup.out
+distclean: clean
+ rm -f *~
+</verb></tscreen>
+<p>
+Per il momento, accontentatevi di questo esempio. Pi&ugrave; avanti aggiungeremo
+una spiegazione ed un bel po' di commenti.
+
+
+<sect> Widget non documentati
+<p>
+Per questi sarebbe utile il contributo degli autori! :) Prendete in
+considerazione la possibilit&agrave; di contribuire al nostro tutorial.
+
+Se dovete usare uno di questi widget non documentati, vi suggeriamo
+caldamente di dare un'occhiata ai loro rispettivi file header nella
+distribuzione di GTK. I nomi delle funzioni di GTK sono molto descrittivi.
+Non appena si capisce come funzionano le cose, non &egrave;
+difficile dedurre il modo d'uso di un widget semplicemente guardando la
+dichiarazione di funzione ad esso associata. Aggiungendo a questo qualche
+spunto tratto dal codice di altri non dovrebbero esserci problemi.
+
+Quando avrete raggiunto una comprensione globale di tutte le funzioni
+di un widget non documentato, considerate la possibilit&agrave; di scrivere
+un tutorial su di esso, in modo che altri possano beneficiare del
+vostro lavoro.
+
+<sect1> Ingressi di testo (Text Entries)
+<p>
+
+<sect1> Selezioni di colore (Color Selections)
+<p>
+
+<sect1> Controlli di intervallo (Range Controls)
+<p>
+
+<sect1> Righelli (Rulers)
+<p>
+
+<sect1> Caselle di testo (Text Boxes)
+<p>
+
+<sect1> Anteprime
+<p>
+
+(Potrebbe essere necessario riscrivere questa parte per conformarsi allo stile
+del resto del tutorial)
+
+<p>
+Le anteprime servono a un certo numero di cose in GIMP/GTK. La pi&ugrave;
+importante &egrave; questa: a risoluzioni molto alte le immagini possono
+facilmente occupare diverse decine di megabyte di memoria; ogni operazione
+su immagini cos&igrave; grosse pu&ograve richiedere molto tempo. Se per la
+scelta di una data modifica vi occorrono 5-10 tentativi (cio&egrave; 10-20
+passi, poich&eacute; &egrave; necessario ripristinare l'originale se si
+&egrave; commesso un errore), possono volerci letteralmente delle ore per
+fare quella giusta - se non si rimane a corto di memoria prima! Coloro che
+hanno passato ore in camera oscura conoscono la sensazione. In questi casi
+le anteprime sono utilissime!
+
+Ma la seccatura dell'attesa non &egrave; l'unico caso. Spesso &egrave; utile
+confrontare la versione precedente con la successiva affiancandole, o almeno
+alternandole. Se si sta lavorando con grandi immagini e ritardi di una decina
+di secondi un confronto efficace &egrave; quantomeno difficile da fare.
+Per immagini di 30 mega (4 pollici per 6 pollici, 600 punti per pollice, 24 bit)
+tale confronto risulta impraticabile per la maggior parte degli utenti. In
+questo caso le anteprime sono di grande aiuto!
+
+Ma c'&egrave; di pi&ugrave;. Con le anteprime &egrave; possibile scrivere
+plug-in per ottenere addirittura anteprime di anteprime (per esempio, la
+simulazione del pacchetto di filtri). Questi plug-in possono cos&igrave;
+fornire un certo numero di anticipazioni di quel che si otterrebbe applicando
+certe opzioni. Un simile approccio funziona come una tavolozza di anteprime,
+ed &egrave; molto efficace per piccoli cambiamenti!
+
+Non &egrave; finita. Per alcuni plug-in pu&ograve; essere necessario un
+intervento umano in tempo reale specifico per ogni immagine. Nel plug-in
+SuperNova, ad esempio, vengono chieste le coordinate del centro della
+futura supernova. Il modo pi&ugrave; semplice per fare questo &egrave;
+senza dubbio quello di mostrare un'anteprima all'utente chiedendogli di
+selezionare interattivamente il centro.
+
+Infine, un paio di applicazioni tipiche. Le anteprime possono essere usate
+anche quando non si sta lavorando con grandi immagini. Per esempio, sono
+utili quando si stanno calcolando dei pattern complicati (date un'occhiata
+al venerabile plug in ``Diffraction'' e a molti altri!). Altro esempio:
+date un'occhiata al plug-in di rotazione della mappa dei colori (in allestimento).
+Le anteprime possono anche essere usate per visualizzare in un plug-in
+piccoli logo o, addirittura, l'immagine dell'Autore!
+
+Quando non usare le anteprime
+
+Le anteprime non vanno usate per grafici, disegni ecc., poich&eacute; per
+queste cose GDK &egrave; molto pi&ugrave; veloce. Le anteprime vanno usate
+solo per immagini derivate da un'elaborazione!
+
+Le anteprime possono essere inserite dappertutto. In un vbox, in un hbox,
+in una tabella, in un bottone, ecc. Sicuramente per&ograve; hanno il loro
+look migliore se bordate con delle cornici (frame). Le anteprime non hanno
+bordi propri e appaiono piatte senza (naturalmente, se quel che si vuole
+&egrave; proprio un aspetto piatto...). I bordi possono essere creati con
+delle cornici.
+
+ [Image][Image]
+
+Le anteprime sono per molti aspetti simili agli altri widget in GTK (con
+tutto ci&ograve; che questo implica), con l'eccezione di avere una
+caratteristica in pi&ugrave;: &egrave; necessario che siano riempite con
+qualche tipo di immagine! Inizialmente parleremo solo dell'aspetto GTK
+delle anteprime e successivamente discuteremo di come riempirle.
+
+Semplicemente:
+
+<tscreen><verb>
+ /* Crea un widget di anteprima,
+ inizializzane le dimensioni
+ e visualizzalo */
+GtkWidget *preview;
+preview=gtk_preview_new(GTK_PREVIEW_COLOR)
+ /* Alternativamente:
+ GTK_PREVIEW_GRAYSCALE);*/
+gtk_preview_size (GTK_PREVIEW (preview), WIDTH, HEIGHT);
+gtk_widget_show(preview);
+my_preview_rendering_function(preview);
+</verb></tscreen>
+
+Come gi&agrave; detto, le anteprime hanno un buon aspetto dentro le cornici,
+quindi:
+
+<tscreen><verb>
+GtkWidget *create_a_preview(int Width,
+ int Height,
+ int Colorfulness)
+{
+ GtkWidget *preview;
+ GtkWidget *frame;
+
+ frame = gtk_frame_new(NULL);
+ gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
+ gtk_container_border_width (GTK_CONTAINER(frame),0);
+ gtk_widget_show(frame);
+
+ preview=gtk_preview_new (Colorfulness?GTK_PREVIEW_COLOR
+ :GTK_PREVIEW_GRAYSCALE);
+ gtk_preview_size (GTK_PREVIEW (preview), Width, Height);
+ gtk_container_add(GTK_CONTAINER(frame),preview);
+ gtk_widget_show(preview);
+
+ my_preview_rendering_function(preview);
+ return frame;
+}
+
+</verb></tscreen>
+
+Questa &egrave; una semplice anteprima. Questa funzione restituisce la cornice
+``madre'', in modo che sia possibile metterla in qualche altro posto nella vostra
+interfaccia. Naturalmente &egrave; possibile passare alla routine la cornice
+madre come parametro. In molte situazioni, comunque, il contenuto di un'anteprima
+viene aggiornato continuamente dall'applicazione; in questi casi potreste
+preferire passare alla funzione ``create_a_preview()'' un puntatore
+all'anteprima, ottenendone cos&igrave; il controllo dopo.
+
+Un'avvertimento pi&ugrave; importante che potrebbe un giorno risparmiarvi
+tanto tempo perso: a volte &egrave; preferibile etichettare le anteprime;
+ad esempio, &egrave; possibile etichettare l'anteprima contenente l'immagine
+originale come ``Originale'' e quella contenente l'immagine modificata come
+``Modificata''. Potrebbe capitarvi di impacchettare in un vbox l'anteprima
+insieme con l'etichetta associata. L'insidia inattesa sta nel fatto che se
+l'etichetta &egrave; pi&ugrave; ampia dell'anteprima (cosa che pu&ograve;
+accadere per una variet&agrave; di motivi da voi non prevedibili, come il
+fatto che la dimensione dell'anteprima viene decisa dinamicamente, o la
+dimensione del font), la cornice si espande e non risulta pi&ugrave;
+perfettamente aderente all'anteprima. Questo stesso problema probabilmente
+pu&ograve; verificarsi anche in altre situazioni.
+
+ [Image]
+
+La soluzione &egrave; quella di mettere l'anteprima e l'etichetta in una
+tabella 2x1 e di legarle insieme chiamando la funzione gtk_table_attach con
+i seguenti parametri (questa &egrave; una delle varianti possibili,
+naturalmente; l'importante &egrave; che non ci sia GTK_FILL nella seconda
+gtk_table_attach):
+
+<tscreen><verb>
+gtk_table_attach(GTK_TABLE(table),label,0,1,0,1,
+ 0,
+ GTK_EXPAND|GTK_FILL,
+ 0,0);
+gtk_table_attach(GTK_TABLE(table),frame,0,1,1,2,
+ GTK_EXPAND,
+ GTK_EXPAND,
+ 0,0);
+</verb></tscreen>
+
+Ed ecco il risultato:
+
+ [Image]
+
+Altri suggerimenti
+
+La maniera pi&ugrave; semplice per rendere cliccabile un'anteprima &egrave;
+quella di metterla dentro un bottone. Questo ha anche l'effetto di aggiungere
+un bel bordo attorno all'anteprima, il che rende superfluo metterla in una
+cornice.
+
+Questo &egrave; tutto per quel che riguarda GTK.
+
+
+Completare un'anteprima
+
+Per impratichirci con le basi del completamento delle anteprime, creiamo
+il seguente disegno (trovato per tentativi):
+
+ [Image]
+
+<tscreen><verb>
+void
+my_preview_rendering_function(GtkWidget *preview)
+{
+#define SIZE 100
+#define HALF (SIZE/2)
+
+ guchar *row=(guchar *) malloc(3*SIZE); /* 3 bits per dot */
+ gint i, j; /* Coordinates */
+ double r, alpha, x, y;
+
+ if (preview==NULL) return; /* Di solito aggiungo questo per */
+ /* evitare piantamenti stupidi. */
+ /* Probabilmente bisognerebbe */
+ /* assicurarsi che tutto sia stato*/
+ /* inizializzato con successo */
+ for (j=0; j < ABS(cos(2*alpha)) ) { /* Siamo dentro la sagoma? */
+ /* glib.h contiene ABS(x). */
+ row[i*3+0] = sqrt(1-r)*255; /* Definisce il Rosso */
+ row[i*3+1] = 128; /* Definisce il Verde */
+ row[i*3+2] = 224; /* Definisce il Blu */
+ } /* "+0" &egrave; per allineamento */
+ else {
+ row[i*3+0] = r*255;
+ row[i*3+1] = ABS(sin((float)i/SIZE*2*PI))*255;
+ row[i*3+2] = ABS(sin((float)j/SIZE*2*PI))*255;
+ }
+ }
+ gtk_preview_draw_row( GTK_PREVIEW(preview),row,0,j,SIZE);
+ /* Inserisce "row" in "preview" a partire del punto avente */
+ /* coordinate (0,j) prima colonna, j-esima riga, per SIZE */
+ /* pixel verso destra */
+ }
+
+ free(row); /* libera un po' di memoria */
+ gtk_widget_draw(preview,NULL); /* indovina cosa fa questo? */
+ gdk_flush(); /* e questo? */
+}
+</verb></tscreen>
+Coloro che non usano GIMP probabilmente hanno gi&agrave; visto abbastanza
+per fare molte cose. Per gli utenti GIMP c'&egrave; ancora qualcosa da
+aggiungere.
+
+Anteprima dell'immagine
+
+Probabilmente &egrave; opportuno tenere pronta una versione ridotta dell'immagine,
+grande quanto basta per riempire l'anteprima. Questo pu&ograve; essere fatto
+selezionando un pixel ogni n, dove n &egrave; il rapporto tra la dimensione
+dell'immagine e la dimensione dell'anteprima. Tutte le operazioni successive
+(compreso il riempimento dell'anteprima) sono fatte solo sul ridotto numero
+di pixel selezionati. Di seguito &egrave; riportata un'implementazione della
+riduzione dell'immagine (si tenga presente che ho preso solo lezioni basilari
+di C!).
+
+
+(ATTENZIONE: CODICE NON VERIFICATO!!!)
+
+<tscreen><verb>
+
+typedef struct {
+ gint width;
+ gint height;
+ gint bbp;
+ guchar *rgb;
+ guchar *mask;
+} ReducedImage;
+
+enum {
+ SELECTION_ONLY,
+ SELCTION_IN_CONTEXT,
+ ENTIRE_IMAGE
+};
+
+ReducedImage *Reduce_The_Image(GDrawable *drawable,
+ GDrawable *mask,
+ gint LongerSize,
+ gint Selection)
+{
+ /* Questa funzione riduce l'immagine alla dimens. scelta per l'anteprima */
+ /* La dimensione dell'anteprima &egrave; determinata da LongerSize, cio&egrave; la pi&ugrave; */
+ /* grande delle dimensioni. Funziona solo per immagini RGB! */
+ gint RH, RW; /* Altezza ridotta e larghezza ridotta */
+ gint width, height; /* Larghezza e altezza dell'area da ridurre */
+ gint bytes=drawable->bpp;
+ ReducedImage *temp=(ReducedImage *)malloc(sizeof(ReducedImage));
+
+ guchar *tempRGB, *src_row, *tempmask, *src_mask_row,R,G,B;
+ gint i, j, whichcol, whichrow, x1, x2, y1, y2;
+ GPixelRgn srcPR, srcMask;
+ gint NoSelectionMade=TRUE; /* Assumiamo di trattare l'intera immagine */
+
+ gimp_drawable_mask_bounds (drawable->id, &amp;x1, &amp;y1, &amp;x2, &amp;y2);
+ width = x2-x1;
+ height = y2-y1;
+ /* Se c'&egrave; una SELEZIONE, ne abbiamo avuto gli estremi! */
+
+ if (width != drawable->width &amp;&amp; height != drawable->height)
+ NoSelectionMade=FALSE;
+ /* Controlliamo se l'utente ha una selezione attiva. Questo */
+ /* diventer&agrave; importante dopo, alla creazione di una maschera ridotta */
+
+ /* Se si vuole l'anteprima dell'immagine intera, annulla quanto sopra */
+ /* Naturalmente, in assenza di una selezione, questo non cambia nulla */
+ if (Selection==ENTIRE_IMAGE) {
+ x1=0;
+ x2=drawable->width;
+ y1=0;
+ y2=drawable->height;
+ }
+
+ /* Se si vuole l'anteprima di una selezione con parte dell'area */
+ /* circostante bisogna espanderla un po'. */
+ if (Selection==SELECTION_IN_CONTEXT) {
+ x1=MAX(0, x1-width/2.0);
+ x2=MIN(drawable->width, x2+width/2.0);
+ y1=MAX(0, y1-height/2.0);
+ y2=MIN(drawable->height, y2+height/2.0);
+ }
+
+ /* Cos&igrave; si determinano larghezza e altezza dell'area da ridurre. */
+ width = x2-x1;
+ height = y2-y1;
+
+ /* Le linee seguenti determinano quale dimensione deve essere il */
+ /* lato pi&ugrave; lungo. L'idea &egrave; presa dal plug-in supernova. Ritengo */
+ /* che avrei potuto pensarci da solo, ma la verit&agrave; va detta. */
+ /* Brutta cosa il plagio! */
+ if (width>height) {
+ RW=LongerSize;
+ RH=(float) height * (float) LongerSize/ (float) width;
+ }
+ else {
+ RH=LongerSize;
+ RW=(float)width * (float) LongerSize/ (float) height;
+ }
+
+ /* L'intera immagine viene "stirata" in una stringa! */
+ tempRGB = (guchar *) malloc(RW*RH*bytes);
+ tempmask = (guchar *) malloc(RW*RH);
+
+ gimp_pixel_rgn_init (&amp;srcPR, drawable, x1, y1, width, height, FALSE, FALSE);
+ gimp_pixel_rgn_init (&amp;srcMask, mask, x1, y1, width, height, FALSE, FALSE);
+
+ /* Prendine abbastanza da contenere una riga di immagine e una di maschera */
+ src_row = (guchar *) malloc (width*bytes);
+ src_mask_row = (guchar *) malloc (width);
+
+ for (i=0; i < RH; i++) {
+ whichrow=(float)i*(float)height/(float)RH;
+ gimp_pixel_rgn_get_row (&amp;srcPR, src_row, x1, y1+whichrow, width);
+ gimp_pixel_rgn_get_row (&amp;srcMask, src_mask_row, x1, y1+whichrow, width);
+
+ for (j=0; j < RW; j++) {
+ whichcol=(float)j*(float)width/(float)RW;
+
+ /* Nessuna selezione = tutti i punti sono completamente selezionati */
+ if (NoSelectionMade)
+ tempmask[i*RW+j]=255;
+ else
+ tempmask[i*RW+j]=src_mask_row[whichcol];
+
+ /* Aggiungi la riga alla lunga stringa che ora contiene l'immagine */
+ tempRGB[i*RW*bytes+j*bytes+0]=src_row[whichcol*bytes+0];
+ tempRGB[i*RW*bytes+j*bytes+1]=src_row[whichcol*bytes+1];
+ tempRGB[i*RW*bytes+j*bytes+2]=src_row[whichcol*bytes+2];
+
+ /* Mantieni anche la trasparenza (alpha) */
+ if (bytes==4)
+ tempRGB[i*RW*bytes+j*bytes+3]=src_row[whichcol*bytes+3];
+ }
+ }
+ temp->bpp=bytes;
+ temp->width=RW;
+ temp->height=RH;
+ temp->rgb=tempRGB;
+ temp->mask=tempmask;
+ return temp;
+}
+</verb></tscreen>
+
+
+La seguente &egrave; una funzione di anteprima che usa lo stesso tipo
+ReducedImage! Si noti che usa una finta trasparenza - se ne &egrave; presente
+una, tramite fake_transparency che &egrave; definita come segue:
+
+<tscreen><verb>
+gint fake_transparency(gint i, gint j)
+{
+ if ( ((i%20)- 10) * ((j%20)- 10)>0 )
+ return 64;
+ else
+ return 196;
+}
+
+</verb></tscreen>
+E adesso la funzione per l'anteprima:
+<tscreen><verb>
+void
+my_preview_render_function(GtkWidget *preview,
+ gint changewhat,
+ gint changewhich)
+{
+ gint Inten, bytes=drawable->bpp;
+ gint i, j, k;
+ float partial;
+ gint RW=reduced->width;
+ gint RH=reduced->height;
+ guchar *row=malloc(bytes*RW);;
+
+
+ for (i=0; i < RH; i++) {
+ for (j=0; j < RW; j++) {
+
+ row[j*3+0] = reduced->rgb[i*RW*bytes + j*bytes + 0];
+ row[j*3+1] = reduced->rgb[i*RW*bytes + j*bytes + 1];
+ row[j*3+2] = reduced->rgb[i*RW*bytes + j*bytes + 2];
+
+ if (bytes==4)
+ for (k=0; k<3; k++) {
+ float transp=reduced->rgb[i*RW*bytes+j*bytes+3]/255.0;
+ row[3*j+k]=transp*a[3*j+k]+(1-transp)*fake_transparency(i,j);
+ }
+ }
+ gtk_preview_draw_row( GTK_PREVIEW(preview),row,0,i,RW);
+ }
+
+ free(a);
+ gtk_widget_draw(preview,NULL);
+ gdk_flush();
+}
+
+Funzioni Applicabili
+
+guint gtk_preview_get_type (void);
+/* No idea */
+void gtk_preview_uninit (void);
+/* No idea */
+GtkWidget* gtk_preview_new (GtkPreviewType type);
+/* Descritta precedentemente */
+void gtk_preview_size (GtkPreview *preview,
+ gint width,
+ gint height);
+/* Permette di ridimensionare un'anteprima esistente */
+/* Pare che un bug in GTK renda disordinato questo */
+/* processo. Un modo di rimettere le cose a posto */
+/* &egrave; quello di ridimensionare manualmente */
+/* la finestra contenente l'anteprima dopo aver */
+/* ridimensionato l'anteprima. */
+
+void gtk_preview_put (GtkPreview *preview,
+ GdkWindow *window,
+ GdkGC *gc,
+ gint srcx,
+ gint srcy,
+ gint destx,
+ gint desty,
+ gint width,
+ gint height);
+/* No idea */
+
+void gtk_preview_put_row (GtkPreview *preview,
+ guchar *src,
+ guchar *dest,
+ gint x,
+ gint y,
+ gint w);
+/* No idea */
+
+void gtk_preview_draw_row (GtkPreview *preview,
+ guchar *data,
+ gint x,
+ gint y,
+ gint w);
+/* Descritta nel testo */
+
+void gtk_preview_set_expand (GtkPreview *preview,
+ gint expand);
+/* No idea */
+
+/* Nessun indizio per le seguenti, ma dovrebbero */
+/* essere standard per la maggior parte dei widget */
+void gtk_preview_set_gamma (double gamma);
+void gtk_preview_set_color_cube (guint nred_shades,
+ guint ngreen_shades,
+ guint nblue_shades,
+ guint ngray_shades);
+void gtk_preview_set_install_cmap (gint install_cmap);
+void gtk_preview_set_reserved (gint nreserved);
+GdkVisual* gtk_preview_get_visual (void);
+GdkColormap* gtk_preview_get_cmap (void);
+GtkPreviewInfo* gtk_preview_get_info (void);
+
+E' tutto!
+
+</verb></tscreen>
+
+
+<sect1> Curve
+<p>
+
+
+<sect>Il Widget EventBox<label id="sec_The_EventBox_Widget">
+<p>
+E' disponibile solo a partire dalla distribuzione gtk+970916.tar.gz.
+<p>
+Alcuni widget gtk non sono associati a finestre X, sicch&eacute;
+semplicemente disegnano sui loro genitori. Per questo motivo essi non possono
+ricevere eventi e se sono sovradimensionati non vengono troncati, ma rischiano
+di sovrapporsi, generando confusione. Se si vuole di pi&ugrave; da questi
+widget si pu&ograve; ricorrere agli EventBox.
+
+A prima vista il widget EventBox potrebbe sembrare completamente inutile. Non
+disegna nulla sullo schermo e non risponde a nessun evento. Tuttavia ha
+una funzione: fornire una finestra X al suo widget figlio. Ci&ograve;
+&egrave; importante in quanto molti widget GTK non hanno una finestra X
+associata. Se questo da una parte risparmia memoria e migliora le prestazioni,
+dall'altra introduce degli svantaggi: un widget senza una finestra X non
+pu&ograve; ricevere eventi, e non taglia in alcun modo il suo contenuto.
+Sebbene il nome ``EventBox'' (casella di eventi) enfasizzi la funzione di
+gestione degli eventi, il widget pu&ograve; essere usato anche per
+limitare la dimensione dei widget figli (ma anche per altro: si veda
+l'esempio seguente).
+
+<p>
+Per creare un widget di tipo EventBox:
+
+<tscreen><verb>
+GtkWidget* gtk_event_box_new (void);
+</verb></tscreen>
+
+<p>
+All'EventBox si pu&ograve aggiungere un widget figlio:
+
+<tscreen><verb>
+gtk_container_add (GTK_CONTAINER(event_box), widget);
+</verb></tscreen>
+
+<p>
+The following example demonstrates both uses of an EventBox - a label
+is created that clipped to a small box, and set up so that a
+mouse-click on the label causes the program to exit.
+Il seguente esempio mostra entrambi gli usi di un EventBox - si crea
+un'etichetta limitata da un rettangolo piccolo, fatta in modo che
+cliccando con il mouse su di essa il programma termina.
+
+<tscreen><verb>
+#include <gtk/gtk.h>
+
+int
+main (int argc, char *argv[])
+{
+ GtkWidget *window;
+ GtkWidget *event_box;
+ GtkWidget *label;
+
+ gtk_init (&amp;argc, &amp;argv);
+
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+
+ gtk_window_set_title (GTK_WINDOW (window), "Event Box");
+
+ gtk_signal_connect (GTK_OBJECT (window), "destroy",
+ GTK_SIGNAL_FUNC (gtk_exit), NULL);
+
+ gtk_container_border_width (GTK_CONTAINER (window), 10);
+
+ /* Crea un EventBox e lo aggiunge alla finestra principale */
+
+ event_box = gtk_event_box_new ();
+ gtk_container_add (GTK_CONTAINER(window), event_box);
+ gtk_widget_show (event_box);
+
+ /* Crea una etichetta lunga */
+
+ label = gtk_label_new ("Click here to quit, quit, quit, quit, quit");
+ gtk_container_add (GTK_CONTAINER (event_box), label);
+ gtk_widget_show (label);
+
+ /* Limitane le dimensioni */
+ gtk_widget_set_usize (label, 110, 20);
+
+ /* E collega ad essa una azione */
+ gtk_widget_set_events (event_box, GDK_BUTTON_PRESS_MASK);
+ gtk_signal_connect (GTK_OBJECT(event_box), "button_press_event",
+ GTK_SIGNAL_FUNC (gtk_exit), NULL);
+
+ /* Un'altra cosa per cui si ha bisogno di una finestra X ... */
+
+ gtk_widget_realize (event_box);
+ gdk_window_set_cursor (event_box->window, gdk_cursor_new (GDK_HAND1));
+
+ gtk_widget_show (window);
+
+ gtk_main ();
+
+ return 0;
+}
+</verb></tscreen>
+
+<sect>Selezionare gli Attributi dei Widget<label id="sec_setting_widget_attributes">
+<p>
+Qui si descrivono le funzioni per la gestione dei widget. Esse possono essere
+usate per impostarne lo stile, il padding, le dimensioni, ...
+
+(Forse andrebbe fatta un'intera sezione sugli acceleratori).
+
+<tscreen><verb>
+void gtk_widget_install_accelerator (GtkWidget *widget,
+ GtkAcceleratorTable *table,
+ gchar *signal_name,
+ gchar key,
+ guint8 modifiers);
+
+void gtk_widget_remove_accelerator (GtkWidget *widget,
+ GtkAcceleratorTable *table,
+ gchar *signal_name);
+
+void gtk_widget_activate (GtkWidget *widget);
+
+void gtk_widget_set_name (GtkWidget *widget,
+ gchar *name);
+gchar* gtk_widget_get_name (GtkWidget *widget);
+
+void gtk_widget_set_sensitive (GtkWidget *widget,
+ gint sensitive);
+
+void gtk_widget_set_style (GtkWidget *widget,
+ GtkStyle *style);
+
+GtkStyle* gtk_widget_get_style (GtkWidget *widget);
+
+GtkStyle* gtk_widget_get_default_style (void);
+
+void gtk_widget_set_uposition (GtkWidget *widget,
+ gint x,
+ gint y);
+void gtk_widget_set_usize (GtkWidget *widget,
+ gint width,
+ gint height);
+
+void gtk_widget_grab_focus (GtkWidget *widget);
+
+void gtk_widget_show (GtkWidget *widget);
+
+void gtk_widget_hide (GtkWidget *widget);
+</verb></tscreen>
+
+
+
+<sect>Funzioni periodiche, di I/O e di attesa<label id="sec_timeouts">
+<p>
+<sect1>Funzioni periodiche
+<p>
+Probabilmente vi sarete chiesti come far fare qualcosa di utile a GTK
+durante la chiamata alla gtk_main(). Ci sono diverse possibilit&agrave;.
+Usando le seguenti funzioni si possono creare funzioni che vengono chiamate
+periodicamente.
+
+<tscreen><verb>
+gint gtk_timeout_add (guint32 interval,
+ GtkFunction function,
+ gpointer data);
+</verb></tscreen>
+
+Il primo argomento &egrave; il numero di millisecondi tra le chiamate alla
+funzione. Il secondo &egrave; la funzione periodica, mentre il terzo
+rappresenta i dati che vengono passati alla funzione. Il valore restituito
+&egrave; un'etichetta che pu&ograve; essere utilizzata per fermare la chiamata
+periodica, passandolo alla funzione:
+
+<tscreen><verb>
+void gtk_timeout_remove (gint tag);
+</verb></tscreen>
+
+La chiamata periodica si ferma anche se la funzione periodica ritorna zero
+o FALSE. Naturalmente questo vuol dire che se si vuole che la funzione periodica
+continui ad essere richiamata, essa deve restituire un valore non nullo,
+cio&egrave; TRUE.
+
+La dichiarazione della funzione periodica dovrebbe essere come questa:
+
+<tscreen><verb>
+gint timeout_callback (gpointer data);
+</verb></tscreen>
+
+<sect1>Controllo dell'I/O
+<p>
+Un'altra utile caratteristica di GTK &egrave; la possibilit&agrave; di fargli
+controllare che siano verificate certe condizioni su un descrittore di file
+(come quelli restituiti da open(2) o socket(2)). Questo &egrave; utile in
+particolar modo per le applicazioni di rete. La funzione &egrave; la seguente:
+
+<tscreen><verb>
+gint gdk_input_add (gint source,
+ GdkInputCondition condition,
+ GdkInputFunction function,
+ gpointer data);
+</verb></tscreen>
+
+Il primo argomento &egrave; il descrittore che si desidera venga controllato,
+mentre il secondo specifica quale condizione si vuole che GDK controlli.
+Questa pu&ograve; essere una tra:
+<p>
+GDK_INPUT_READ - Chiama la funzione quando ci sono dati pronti per la lettura
+nel descrittore di file.
+<p>
+GDK_INPUT_WRITE - Chiama la funzione quando il descrittore di file &egrave;
+pronto per la scrittura.
+<p>
+Come sicuramente avrete gi&agrave; intuito, il terzo parametro &egrave; la
+funzione da chiamare quando la condizione specificata &egrave; soddisfatta,
+mentre il quarto rappresenta i dati da passare a questa funzione.
+<p>
+Il valore di ritorno &egrave; un etichetta che pu&ograve; essere usata per
+fermare il controllo di GDK sul descrittore di file, usando la seguente
+funzione:
+<p>
+<tscreen><verb>
+void gdk_input_remove (gint tag);
+</verb></tscreen>
+<p>
+La funzione da richiamare va dichiarata cos&igrave;:
+<p>
+<tscreen><verb>
+void input_callback (gpointer data, gint source,
+ GdkInputCondition condition);
+</verb></tscreen>
+<p>
+
+<sect1>Funzioni di attesa (``Idle'')
+<p>
+Cosa fare se si ha una funzione che si vuole venga chiamata quando non
+sta accadendo nient'altro?
+
+<tscreen><verb>
+gint gtk_idle_add (GtkFunction function,
+ gpointer data);
+</verb></tscreen>
+
+Questa fa si che GDK chiami la funzione specificata quando non c'&egrave;
+nessuna altra operazione in corso.
+
+<tscreen><verb>
+void gtk_idle_remove (gint tag);
+</verb></tscreen>
+<p>
+Non ci soffermeremo sul significato dei parametri in quanto del tutto analoghi
+ai precedenti. La funzione puntata dal primo argomento della gtk_idle_add
+viene chiamata non appena se ne presenta l'opportunit&agrave;; come
+negli altri casi, se essa restituisce FALSE non viene pi&ugrave; chiamata.
+
+
+<sect>La gestione delle selezioni
+
+<sect1> Overview
+
+<p>
+
+Le <em>selezioni</em> sono un tipo di comunicazione tra processi
+supportato da GTK. Una selezione identifica un frammento di dati; per
+esempio, una porzione di testo selezionata dall'utente in qualche modo,
+magari con il mouse. Su un display solo un'applicazione alla volta
+(il <em>proprietario</em>) pu&oacute; essere proprietaria di una
+particolare selezione, sicch&eacute; quando un'applicazione richiede
+una selezione il precedente proprietario deve comunicare all'utente che
+la selezione &egrave; stata ceduta. Altre applicazioni possono richiedere
+il contenuto di una selezione in diverse forme, chiamate <em>obiettivi</em>.
+Ci pu&ograve; essere un numero qualsiasi di selezioni, ma la maggior parte
+delle applicazioni X pu&ograve; gestirne solo una, la <em>selezione
+primaria</em>.
+
+<p>
+Nella maggior parte dei casi per una applicazione GTK non &egrave;
+necessario gestire esplicitamente le selezioni. I widget standard,
+come quello di Ingresso, hanno gi&agrave; la capacit&agrave; di
+chiedere la selezione se necessario (p. e., quando l'utente
+seleziona sul testo), e di recuperare il contenuto di una selezione
+di un altro widget o di un'altra applicazione (p. e., quando l'utente
+clicca il tasto centrale del mouse). Ci possono comunque essere dei
+casi nei quali si vuole dare ad altri widget la capacit&agrave; di
+fornire la selezione, o si vogliono recuperare degli obiettivi non
+supportati direttamente.
+
+<p>
+Un concetto fondamentale necessario per comprendere la gestione delle
+selezioni &egrave; quello di <em>atomo</em>. Un atomo &egrave; un intero
+che identifica univocamente una stringa (su un certo display).
+Certi atomi sono predefiniti dal server X, e in alcuni casi in <tt>gtk.h</tt>
+ci sono costanti corrispondenti a questi atomi. Per esempio, la costante
+<tt>GDK_PRIMARY_SELECTION</tt> corrisponde alla stringa ``PRIMARY''.
+Negli altri casi bisogna usare le funzioni <tt>gdk_atom_intern()</tt>
+per ottenere l'atomo corrispondente ad una stringa, e <tt>gdk_atom_name()</tt>
+per ottenere il nome di un atomo. Sia le selezioni sia gli obiettivi sono
+identificati da atomi.
+
+<sect1> Recuperare le selezioni
+
+<p>
+
+Il recupero di una selezione &egrave; un processo asincrono. Per iniziare
+il processo, si chiama:
+<tscreen><verb>
+gint gtk_selection_convert (GtkWidget *widget,
+ GdkAtom selection,
+ GdkAtom target,
+ guint32 time)
+</verb</tscreen>
+
+Questo <em>converte</em> la selezione nella forma specificata
+dall'obiettivo <tt/target/. Se possibile, il campo <tt/time/
+dovrebbe essere il tempo dell'evento che ha attivato la selezione.
+Questo aiuta a far si che gli eventi avvengano nell'ordine in cui
+l'utente li ha richiesti. Se comunque non fosse disponibile (per
+esempio, se la conversione &egrave; stata attivata da un segnale di
+``cliccato''), allora si pu&ograve; usare la costante
+<tt>GDK_CURRENT_TIME</tt>.
+
+<p>
+Quando il proprietario di una selezione risponde ad una richiesta,
+un segnale ``selection_received'' (selezione ricevuta) viene inviato
+alla vostra applicazione. Il gestore di questo segnale riceve un
+puntatore ad una struttura <tt>GtkSelectionData</tt>, che &egrave;
+definita nel modo seguente:
+<tscreen><verb>
+struct _GtkSelectionData
+{
+ GdkAtom selection;
+ GdkAtom target;
+ GdkAtom type;
+ gint format;
+ guchar *data;
+ gint length;
+};
+</verb></tscreen>
+<tt>selection</tt> e <tt>target</tt> sono i valori da voi specificati
+nella chiamata <tt>gtk_selection_convert()</tt>. <tt>type</tt> &egrave;
+un atomo che identifica il tipo di dati restituiti dal proprietario della
+selezione. Alcuni valori possibili sono ``STRING'', una stringa di
+caratteri latin-1, ``ATOM'', una serie di atomi, ``INTEGER'', un intero, ecc.
+La maggior parte degli obiettivi pu&ograve; restituire solo un tipo.
+<tt/format/ ci d&agrave; la lunghezza delle unit&agrave; (per esempio caratteri)
+in bit. Di solito, quando si ricevono i dati non ci si cura di questo.
+<tt>data</tt> &egrave; un puntatore ai dati restituiti, e <tt>length</tt>
+&egrave; la lunghezza dei dati restituiti, in byte. Se <tt>length</tt>
+&egrave; negativo allora si &egrave; verificato un errore e non &egrave;
+stato possibile recuperare la selezione. Questo pu&ograve; avvenire se
+nessuna applicazione era proprietaria della selezione, o se si &egrave;
+richiesto un obiettivo non supportato dall'applicazione. Viene garantito
+che il buffer sia un byte pi&ugrave; lungo di <tt>length</tt>; il byte
+in pi&ugrave; sar&agrave; sempre zero, in modo che non sia necessario
+ricopiare le stringhe solo per farle terminare con zero.
+
+<p>
+Nell'esempio che segue viene recuperato l'obiettivo speciale ``TARGETS'',
+che &egrave; una lista di tutti gli obiettivi in cui pu&ograve; essere
+convertita la selezione.
+<tscreen><verb>
+#include <gtk/gtk.h>
+
+void selection_received (GtkWidget *widget,
+ GtkSelectionData *selection_data,
+ gpointer data);
+
+/* Gestore di segnale chiamato quando l'utente clicca nel bottone */
+/* "Get Targets" */
+void
+get_targets (GtkWidget *widget, gpointer data)
+{
+ static GdkAtom targets_atom = GDK_NONE;
+
+ /* Prende l'atomo corrispondente alla stringa "TARGETS" */
+ if (targets_atom == GDK_NONE)
+ targets_atom = gdk_atom_intern ("TARGETS", FALSE);
+
+ /* E richiede l'obiettivo "TARGETS" per la selezione primaria */
+ gtk_selection_convert (widget, GDK_SELECTION_PRIMARY, targets_atom,
+ GDK_CURRENT_TIME);
+}
+
+/* Gestore di segnale chiamato quando il proprietario della selezione */
+/* restituisce i dati */
+void
+selection_received (GtkWidget *widget, GtkSelectionData *selection_data,
+ gpointer data)
+{
+ GdkAtom *atoms;
+ GList *item_list;
+ int i;
+
+ /* **** IMPORTANTE **** Controlla che il recupero sia riuscito */
+ if (selection_data->length < 0)
+ {
+ g_print ("Selection retrieval failed\n");
+ return;
+ }
+ /* Make sure we got the data in the expected form */
+ if (selection_data->type != GDK_SELECTION_TYPE_ATOM)
+ {
+ g_print ("Selection \"TARGETS\" was not returned as atoms!\n");
+ return;
+ }
+
+ /* Stampa gli atomi ricevuti */
+ atoms = (GdkAtom *)selection_data->data;
+
+ item_list = NULL;
+ for (i=0; i<selection_data->length/sizeof(GdkAtom); i++)
+ {
+ char *name;
+ name = gdk_atom_name (atoms[i]);
+ if (name != NULL)
+ g_print ("%s\n",name);
+ else
+ g_print ("(bad atom)\n");
+ }
+
+ return;
+}
+
+int
+main (int argc, char *argv[])
+{
+ GtkWidget *window;
+ GtkWidget *button;
+
+ gtk_init (&amp;argc, &amp;argv);
+
+ /* Create the toplevel window */
+
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ gtk_window_set_title (GTK_WINDOW (window), "Event Box");
+ gtk_container_border_width (GTK_CONTAINER (window), 10);
+
+ gtk_signal_connect (GTK_OBJECT (window), "destroy",
+ GTK_SIGNAL_FUNC (gtk_exit), NULL);
+
+ /* Crea un bottone che l'utente pu&ograve; cliccare per ottenere gli obiettivi */
+
+ button = gtk_button_new_with_label ("Get Targets");
+ gtk_container_add (GTK_CONTAINER (window), button);
+
+ gtk_signal_connect (GTK_OBJECT(button), "clicked",
+ GTK_SIGNAL_FUNC (get_targets), NULL);
+ gtk_signal_connect (GTK_OBJECT(button), "selection_received",
+ GTK_SIGNAL_FUNC (selection_received), NULL);
+
+ gtk_widget_show (button);
+ gtk_widget_show (window);
+
+ gtk_main ();
+
+ return 0;
+}
+</verb></tscreen>
+
+<sect1> Fornire una selezione
+
+<p>
+Fornire la selezione &egrave; un po' pi&ugrave; complicato. Bisogna
+registrare i gestori che verranno chiamati quando viene richiesta la
+propria selezione. Per ogni coppia selezione/obiettivo che si gestir&agrave;
+occorre una chiamata a:
+
+<tscreen><verb>
+void gtk_selection_add_handler (GtkWidget *widget,
+ GdkAtom selection,
+ GdkAtom target,
+ GtkSelectionFunction function,
+ GtkRemoveFunction remove_func,
+ gpointer data);
+</verb></tscreen>
+
+<tt/widget/, <tt/selection/, e <tt/target/ identificano le richieste
+che questo gestore soddisfer&agrave;. <tt/remove_func/, se non &egrave;
+NULL, verr&agrave; chiamato quando il gestore di segnale viene rimosso.
+Questo &egrave; utile, per esempio, per linguaggi interpretati ai quali
+serve di tener traccia di un conteggio di riferimento per <tt/data/.
+
+<p>
+La funzione di richiamo ha la forma:
+
+<tscreen><verb>
+typedef void (*GtkSelectionFunction) (GtkWidget *widget,
+ GtkSelectionData *selection_data,
+ gpointer data);
+
+</verb></tscreen>
+
+La GtkSelectionData &egrave; la stessa di prima, ma stavolta siamo
+responsabili di riempire i campi <tt/type/, <tt/format/, <tt/data/,
+e <tt/length/. (Il campo <tt/format/ qui &egrave; effettivamente
+importante - il server X lo usa per capire se occorre che i byte
+dei dati vengano scambiati o no. Di solito sar&agrave; 8 - cio&egrave;
+un carattere - o 32 - cio&egrave; un intero.) Questo viene fatto
+chiamando la funzione:
+
+<tscreen><verb>
+void gtk_selection_data_set (GtkSelectionData *selection_data,
+ GdkAtom type,
+ gint format,
+ guchar *data,
+ gint length);
+</verb></tscreen>
+Questa funzione si prende cura di fare propriamente una copia dei dati
+in modo che non ci si debba preoccupare di conservarli (&egrave; opportuno
+evitare di riempire a mano i campi della struttura GtkSelectionData).
+
+<p>
+Quando richiesto dall'utente, richiederete la propriet&agrave; della selezione
+chiamando:
+
+<tscreen><verb>
+gint gtk_selection_owner_set (GtkWidget *widget,
+ GdkAtom selection,
+ guint32 time);
+</verb></tscreen>
+
+Se un'altra applicazione richiede la propriet&agrave; della selezione,
+riceverete un evento di azzeramento della selezione (``selection_clear_event'').
+
+Come esempio di fornitura della selezione, il programma seguente aggiunge
+la funzionalit&agrave; di selezione a un bottone di attivazione. Quando il
+bottone viene premuto, il programma richiede la selezione primaria.
+L'unico obiettivo supportato (oltre a certi obiettivi come ``TARGETS''
+fornito dalla stessa GTK) &egrave; l'obiettivo ``STRING''. Quando viene
+richiesto questo obiettivo, viene restituita una rappresentazione stringa
+del tempo.
+
+<tscreen><verb>
+#include <gtk/gtk.h>
+#include <time.h>
+
+/* Richiamata quando l'utente attiva la selezione */
+void
+selection_toggled (GtkWidget *widget, gint *have_selection)
+{
+ if (GTK_TOGGLE_BUTTON(widget)->active)
+ {
+ *have_selection = gtk_selection_owner_set (widget,
+ GDK_SELECTION_PRIMARY,
+ GDK_CURRENT_TIME);
+ /* se il richiamo della selezione &egrave; fallito, si riporta il
+ bottone nello stato non premuto */
+ if (!*have_selection)
+ gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON(widget), FALSE);
+ }
+ else
+ {
+ if (*have_selection)
+ {
+ /* Prima di annullare la selezione mettendone a NULL il proprietario,
+ controlliamo se siamo i veri proprietari */
+ if (gdk_selection_owner_get (GDK_SELECTION_PRIMARY) == widget->window)
+ gtk_selection_owner_set (NULL, GDK_SELECTION_PRIMARY,
+ GDK_CURRENT_TIME);
+ *have_selection = FALSE;
+ }
+ }
+}
+
+/* Chiamata quando un'altra applicazione richiede la selezione */
+gint
+selection_clear (GtkWidget *widget, GdkEventSelection *event,
+ gint *have_selection)
+{
+ *have_selection = FALSE;
+ gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON(widget), FALSE);
+
+ return TRUE;
+}
+
+/* Fornisce come selezione il tempo attuale */
+void
+selection_handle (GtkWidget *widget,
+ GtkSelectionData *selection_data,
+ gpointer data)
+{
+ gchar *timestr;
+ time_t current_time;
+
+ current_time = time (NULL);
+ timestr = asctime (localtime(&amp;current_time));
+ /* Quando si restituisce una singola stringa, non occorre che finisca
+ con NULL. Questo verr&agrave; fatto automaticamente */
+
+ gtk_selection_data_set (selection_data, GDK_SELECTION_TYPE_STRING,
+ 8, timestr, strlen(timestr));
+}
+
+int
+main (int argc, char *argv[])
+{
+ GtkWidget *window;
+
+ GtkWidget *selection_button;
+
+ static int have_selection = FALSE;
+
+ gtk_init (&amp;argc, &amp;argv);
+
+ /* Crea la finestra di livello superiore */
+
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ gtk_window_set_title (GTK_WINDOW (window), "Event Box");
+ gtk_container_border_width (GTK_CONTAINER (window), 10);
+
+ gtk_signal_connect (GTK_OBJECT (window), "destroy",
+ GTK_SIGNAL_FUNC (gtk_exit), NULL);
+
+ /* Crea un bottone a commutazione che agisce come la selezione */
+
+ selection_button = gtk_toggle_button_new_with_label ("Claim Selection");
+ gtk_container_add (GTK_CONTAINER (window), selection_button);
+ gtk_widget_show (selection_button);
+
+ gtk_signal_connect (GTK_OBJECT(selection_button), "toggled",
+ GTK_SIGNAL_FUNC (selection_toggled), &amp;have_selection);
+ gtk_signal_connect (GTK_OBJECT(selection_button), "selection_clear_event",
+ GTK_SIGNAL_FUNC (selection_clear), &amp;have_selection);
+
+ gtk_selection_add_handler (selection_button, GDK_SELECTION_PRIMARY,
+ GDK_SELECTION_TYPE_STRING,
+ selection_handle, NULL, NULL);
+
+ gtk_widget_show (selection_button);
+ gtk_widget_show (window);
+
+ gtk_main ();
+
+ return 0;
+}
+</verb></tscreen>
+
+
+
+<sect>La glib<label id="sec_glib">
+<p>
+La glib fornisce molte funzioni e definizioni utili pronte all'uso quando si
+creano applicazioni GDK e GTK. Qui verranno elencate tutte, con una
+breve spiegazione. Molte sono duplicati delle funzioni standard della libc,
+e quindi per queste non si scender&agrave; nei dettagli. Questa vuole essere una
+lista di riferimento, in modo che si sappia cosa &egrave; possibile usare.
+
+<sect1>Definizioni
+<p>
+Le definizioni per gli estremi di molti dei tipi standard sono:
+
+<tscreen><verb>
+G_MINFLOAT
+G_MAXFLOAT
+G_MINDOUBLE
+G_MAXDOUBLE
+G_MINSHORT
+G_MAXSHORT
+G_MININT
+G_MAXINT
+G_MINLONG
+G_MAXLONG
+</verb></tscreen>
+
+Ci sono anche le seguenti definizioni di tipo. Quelle rimaste non specificate
+sono dipendenti dall'architettura. Si ricordi di evitare di fare affidamento
+sulla dimensione di un puntatore se si vuole la portabilit&agrave;! P.e., un puntatore
+su un Alpha &egrave; lungo 8 byte, ma 4 su un Intel.
+
+<tscreen><verb>
+char gchar;
+short gshort;
+long glong;
+int gint;
+char gboolean;
+
+unsigned char guchar;
+unsigned short gushort;
+unsigned long gulong;
+unsigned int guint;
+
+float gfloat;
+double gdouble;
+long double gldouble;
+
+void* gpointer;
+
+gint8
+guint8
+gint16
+guint16
+gint32
+guint32
+</verb></tscreen>
+
+<sect1>Liste a doppio collegamento
+<p>
+le seguenti funzioni sono usate per creare, gestire e distruggere liste a
+doppio collegamento. Si assume che il lettore sappia gi&agrave; cosa sono le liste
+collegate, poich&eacute; descriverle &egrave; fuori dagli scopi di questo documento.
+Naturalmente non &egrave; necessario conoscerle per l'uso generale di GTK, per
+quanto conoscerle sia comunque interessante.
+
+<tscreen><verb>
+GList* g_list_alloc (void);
+
+void g_list_free (GList *list);
+
+void g_list_free_1 (GList *list);
+
+GList* g_list_append (GList *list,
+ gpointer data);
+
+GList* g_list_prepend (GList *list,
+ gpointer data);
+
+GList* g_list_insert (GList *list,
+ gpointer data,
+ gint position);
+
+GList* g_list_remove (GList *list,
+ gpointer data);
+
+GList* g_list_remove_link (GList *list,
+ GList *link);
+
+GList* g_list_reverse (GList *list);
+
+GList* g_list_nth (GList *list,
+ gint n);
+
+GList* g_list_find (GList *list,
+ gpointer data);
+
+GList* g_list_last (GList *list);
+
+GList* g_list_first (GList *list);
+
+gint g_list_length (GList *list);
+
+void g_list_foreach (GList *list,
+ GFunc func,
+ gpointer user_data);
+</verb></tscreen>
+
+
+<sect1>Liste a collegamento singolo
+<p>
+Molte delle funzioni per le liste a collegamento singolo sono identiche alle
+precedenti. Eccone una lista completa:
+<tscreen><verb>
+GSList* g_slist_alloc (void);
+
+void g_slist_free (GSList *list);
+
+void g_slist_free_1 (GSList *list);
+
+GSList* g_slist_append (GSList *list,
+ gpointer data);
+
+GSList* g_slist_prepend (GSList *list,
+ gpointer data);
+
+GSList* g_slist_insert (GSList *list,
+ gpointer data,
+ gint position);
+
+GSList* g_slist_remove (GSList *list,
+ gpointer data);
+
+GSList* g_slist_remove_link (GSList *list,
+ GSList *link);
+
+GSList* g_slist_reverse (GSList *list);
+
+GSList* g_slist_nth (GSList *list,
+ gint n);
+
+GSList* g_slist_find (GSList *list,
+ gpointer data);
+
+GSList* g_slist_last (GSList *list);
+
+gint g_slist_length (GSList *list);
+
+void g_slist_foreach (GSList *list,
+ GFunc func,
+ gpointer user_data);
+
+</verb></tscreen>
+
+<sect1>Gestione della memoria
+<p>
+<tscreen><verb>
+gpointer g_malloc (gulong size);
+</verb></tscreen>
+
+Questa &egrave; una sostituta di malloc(). Non occorre controllare il valore
+restituito, in quanto lo fa gi&agrave; questa funzione.
+
+<tscreen><verb>
+gpointer g_malloc0 (gulong size);
+</verb></tscreen>
+
+Come la precedente, ma la memoria viene azzerata prima di restituire un
+puntatore ad essa.
+
+<tscreen><verb>
+gpointer g_realloc (gpointer mem,
+ gulong size);
+</verb></tscreen>
+
+Riloca ``size'' byte di memoria che inizia a ``mem''. Ovviamente, la memoria
+dovrebbe essere stata allocata precedentemente.
+
+<tscreen><verb>
+void g_free (gpointer mem);
+</verb></tscreen>
+
+Libera la memoria. Facile!
+
+<tscreen><verb>
+void g_mem_profile (void);
+</verb></tscreen>
+
+Emette un profilo della memoria usata, ma occorre ricompilare e reinstallare
+la libreria aggiungendo #define MEM_PROFILE all'inizio del file glib/gmem.c.
+
+<tscreen><verb>
+void g_mem_check (gpointer mem);
+</verb></tscreen>
+
+Controlla che una locazione di memoria sia valida. Occorre ricompilare e
+reinstallare la libreria aggiungendo #define MEM_CHECK all'inizio del file
+gmem.c.
+
+<sect1>Timer
+<p>
+Funzioni legate ai timer...
+
+<tscreen><verb>
+GTimer* g_timer_new (void);
+
+void g_timer_destroy (GTimer *timer);
+
+void g_timer_start (GTimer *timer);
+
+void g_timer_stop (GTimer *timer);
+
+void g_timer_reset (GTimer *timer);
+
+gdouble g_timer_elapsed (GTimer *timer,
+ gulong *microseconds);
+</verb></tscreen>
+
+<sect1>Gestione delle stringhe
+<p>
+Un'accozzaglia di funzioni per la gestione delle stringhe. Sembrano tutte molto
+interessanti, e probabilmente migliori per molte caratteristiche delle funzioni
+standard del C per le stringhe, ma necessitano di documentazione.
+
+<tscreen><verb>
+GString* g_string_new (gchar *init);
+void g_string_free (GString *string,
+ gint free_segment);
+
+GString* g_string_assign (GString *lval,
+ gchar *rval);
+
+GString* g_string_truncate (GString *string,
+ gint len);
+
+GString* g_string_append (GString *string,
+ gchar *val);
+
+GString* g_string_append_c (GString *string,
+ gchar c);
+
+GString* g_string_prepend (GString *string,
+ gchar *val);
+
+GString* g_string_prepend_c (GString *string,
+ gchar c);
+
+void g_string_sprintf (GString *string,
+ gchar *fmt,
+ ...);
+
+void g_string_sprintfa (GString *string,
+ gchar *fmt,
+ ...);
+</verb></tscreen>
+
+<sect1>Funzioni d'utilit&agrave; e di errore
+<p>
+<tscreen><verb>
+gchar* g_strdup (const gchar *str);
+</verb></tscreen>
+
+Funzione sostitutiva della strdup. Copia i contenuti originari delle stringhe
+in memoria appena allocata, restituendo un puntatore ad essa.
+
+<tscreen><verb>
+gchar* g_strerror (gint errnum);
+</verb></tscreen>
+Si raccomanda di usare questa gunzione per tutti i messaggi di errore. E' molto
+pi&ugrave; graziosa, e pi&ugrave; portabile di perror() o di altre. L'output di solito ha la
+forma:
+
+<tscreen><verb>
+nome programma:funzione fallita:file o altre descrizioni:strerror
+</verb></tscreen>
+
+Di seguito un esempio di una chiamata di questo tipo usata nel nostro
+programma Hello World:
+
+<tscreen><verb>
+g_print("hello_world:open:%s:%s\n", filename, g_strerror(errno));
+</verb></tscreen>
+
+<tscreen><verb>
+void g_error (gchar *format, ...);
+</verb></tscreen>
+
+Visualizza un messaggio di errore. Il formato &egrave; come quello di printf,
+ma prepone ``** ERROR **: '' al messaggio e termina il programma. Da usare solo
+per errori gravi.
+
+<tscreen><verb>
+void g_warning (gchar *format, ...);
+</verb></tscreen>
+
+Come la precedente, ma prepone ``** WARNING **: '' e non termina il programma.
+
+<tscreen><verb>
+void g_message (gchar *format, ...);
+</verb></tscreen>
+
+Visualizza ``message: '' e poi il messaggio.
+
+<tscreen><verb>
+void g_print (gchar *format, ...);
+</verb></tscreen>
+
+Sostituta di printf().
+
+L'ultima funzione:
+
+<tscreen><verb>
+gchar* g_strsignal (gint signum);
+</verb></tscreen>
+
+Visualizza il nome del messaggio del sistema Unix associato al numero di
+segnale. Utile nelle funzioni generiche di gestione dei segnali.
+
+Tutte le funzioni elencate sono pi&ugrave; o meno prese da glib.h. Se qualcuno volesse
+documentare qualche funzione, mandi una email all'autore!
+
+<sect>I file rc di GTK
+<p>
+GTK ha un suo modo di trattare le preferenze delle applicazioni, usando
+i file rc. Questi possono essere usati per scegliere i colori di quasi tutti
+i widget, e possono anche essere usati per inserire delle pixmap nello sfondo
+di alcuni widget.
+
+<sect1>Funzioni per i file rc
+<p>
+All'inizio della vostra applicazione dovrebbe esserci una chiamata a
+<tscreen><verb>
+void gtk_rc_parse (char *filename);
+</verb></tscreen>
+<p>
+passando come parametro il nome del vostro file rc. Questo far&agrave; si che GTK
+analizzi tale file e usi le impostazioni di stile per i tipi di widget ivi
+definite.
+<p>
+Se si desidera avere un insieme speciale di widget che abbia uno stile diverso
+dagli altri, o qualsiasi altra divisione logica dei widget, si chiami
+<tscreen><verb>
+void gtk_widget_set_name (GtkWidget *widget,
+ gchar *name);
+</verb></tscreen>
+<p>
+passando un widget appena creato come primo argomento, e il nome che gli si
+vuole dare come secondo. Questo consentir&agrave; di cambiare gli attributi di
+questo widget per nome tramite il file rc.
+<p>
+Effettuando una chiamata come questa:
+
+<tscreen><verb>
+button = gtk_button_new_with_label ("Special Button");
+gtk_widget_set_name (button, "special button");
+</verb></tscreen>
+<p>
+allora a questo bottone viene dato il nome ``special button'' ed esso pu&ograve; essere
+riferito per nome nel file rc come ``special button.GtkButton''. [<--- Verificatemi!]
+<p>
+Il seguente esempio di file rc imposta le propriet&agrave; della finestra principale,
+e fa si che tutti i figli di questa finestra ereditino lo stile descritto
+dallo stile ``main button''. Il codice usato nell'applicazione &egrave;:
+
+<tscreen><verb>
+window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+gtk_widget_set_name (window, "main window");
+</verb></tscreen>
+<p>
+Lo stile viene definito nel file rc usando:
+
+<tscreen><verb>
+widget "main window.*GtkButton*" style "main_button"
+</verb></tscreen>
+<p>
+che assegna a tutti i widget GtkButton nella finestra principale lo stile
+``main_buttons'' secondo la definizione data nel file rc.
+<p>
+Come si pu&ograve; vedere, questo sistema &egrave; molto potente e flessibile. Usate la
+vostra immaginazione per trarre il massimo vantaggio da esso.
+
+<sect1>Il formato dei file rc di GTK
+<p>
+Nell'esempio che segue viene illustrato il formato del file GTK. Si tratta
+del file testgkrc dalla distribuzione del GTK, a cui sono stati aggiunti
+vari commenti e varie cose. Potete includere questa spiegazione nella
+vostra applicazione per consentire all'utente di personalizzarla finemente.
+<p>
+There are several directives to change the attributes of a widget.
+Ci sono diverse direttive per cambiare gli attributi di un widget.
+<itemize>
+<item>fg - Assegna il colore di primo piano di un widget.
+<item>bg - Assegna il colore di sfondo di un widget.
+<item>bg_pixmap - Inserisce nello sfondo di un widget una pixmap.
+<item>font - Sceglie il font da usarsi con il dato widget.
+</itemize>
+<p>
+Inoltre ci sono diversi stati in cui pu&ograve; trovarsi un widget, e si possono
+assegnare diversi colori, pixmap e font per ogni stato. Essi sono:
+<itemize>
+<item>NORMAL - Lo stato normale di un widget, quando il mouse non si trova su
+di esso, quando non &egrave; premuto, ecc.
+<item>PRELIGHT (evidenziato)- Quando il mouse si trova sopra al widget
+verranno usati i colori assegnati per questo stato.
+<item>ACTIVE (attivo) - Quando il widget &egrave; premuto o cliccato esso sar&agrave; attivo,
+e verranno usati gli attributi assegnati da questa etichetta.
+<item>INSENSITIVE (insensibile)- Quando un widget viene reso insensibile,
+e non pu&ograve; essere attivato, prender&agrave; questi attributi.
+<item>SELECTED (selezionato) - Quando un oggetto viene selezionato, prende
+questi attributi.
+</itemize>
+<p>
+Quando si usano le parole chiave ``fg'' e ``bg'' per assegnare i colori dei
+widget il formato &egrave;:
+<tscreen><verb>
+fg[<STATE>] = { Rosso, Verde, Blu }
+</verb></tscreen>
+<p>
+Dove STATE &egrave; uno degli stati visti prima (PRELIGHT, ACTIVE ecc.), e Rosso,
+Verde e Blu sono valori nell'intervallo 0 - 1.0; { 1.0, 1.0, 1.0 } rappresenta
+il bianco.
+Devono essere in formato float, o verranno visti come 0, sicch&eacute; un ``1'' diretto
+non funziona, deve essere ``1.0''. Uno ``0'' diretto va invece bene, poich&eacute; poco
+importa se non viene riconosciuto: valori non riconosciuti vengono considerati
+0.
+<p>
+bg_pixmap &egrave; molto simile al precedente, tranne per i colori che vengono
+sostituiti dal nome di un file.
+
+pixmap_path &egrave; una lista di percorsi separati da ``:''. In questi percorsi vengono
+cercate le pixmap specificate.
+<p>
+La direttiva font &egrave; semplicemente:
+<tscreen><verb>
+font = "<font name>"
+</verb></tscreen>
+<p>
+dove l'unica parte complicata &egrave; immaginare la stringa del font. Allo scopo
+pu&ograve; servire usare xfontsel o una utilit&agrave; analoga.
+<p>
+``widget_class'' assegna lo stile di una classe di widget. Queste classi sono
+elencate nell'introduzione ai widget sulla gerarchia delle classi.
+<p>
+La direttiva ``widget'' assegna un insieme di widget dal nome specificato ad
+un dato stile, annullando qualsiasi stile assegnato per la data classe di widget.
+Questi widget vengono registrati nell'applicazione usando la chiamata
+gtk_widget_set_name(). Questo consente di specificare gli attributi di un
+widget singlarmente, piuttosto che assegnando gli attributi di un'intera classe
+di widget. E' opportuno documentare tutti questi widget speciali in modo che
+gli utenti possano personalizzarli.
+<p>
+Quando la parola chiave ``<tt>parent</>'' viene usata come un attributo, il
+widget erediter&agrave; gli attributi del suo genitore nell'applicazione.
+<p>
+Quando si definisce uno stile si possono assegnare gli attributi di uno
+stile definito precedentemente a quello nuovo.
+<tscreen><verb>
+style "main_button" = "button"
+{
+ font = "-adobe-helvetica-medium-r-normal--*-100-*-*-*-*-*-*"
+ bg[PRELIGHT] = { 0.75, 0, 0 }
+}
+</verb></tscreen>
+<p>
+Questo esempio prende lo stile ``button'' e crea un nuovo stile
+semplicemente cambiando il font e il colore di sfondo dello stato ``prelight''
+nello stile ``button''.
+<p>
+Naturalmente, molti di questi attributi non sono applicabili a tutti i widget.
+E' veramente un semplice problema di buon senso. Tutto quello che potrebbe
+applicarsi, dovrebbe.
+
+<sect1>Esempio di file rc
+<p>
+
+<tscreen><verb>
+# pixmap_path "<dir 1>:<dir 2>:<dir 3>:..."
+#
+pixmap_path "/usr/include/X11R6/pixmaps:/home/imain/pixmaps"
+#
+# style <name> [= <name>]
+# {
+# <option>
+# }
+#
+# widget <widget_set> style <style_name>
+# widget_class <widget_class_set> style <style_name>
+
+
+# Ecco una lista di tutti gli stati possibili. Si noti che alcuni non sono
+# applicabili a certi widget.
+#
+# NORMAL - Lo stato normale di un widget, quando il mouse non si trova su
+# di esso, quando non &egrave; premuto, ecc.
+#
+# PRELIGHT (evidenziato)- Quando il mouse si trova sopra al widget
+# verranno usati i colori assegnati per questo stato.
+#
+# ACTIVE (attivo) - Quando il widget &egrave; premuto o cliccato esso sar&agrave; attivo,
+# e verranno usati gli attributi assegnati da questa etichetta.
+#
+# INSENSITIVE (insensibile)- Quando un widget viene reso insensibile,
+# e non pu&ograve; essere attivato, prender&agrave; questi attributi.
+#
+# SELECTED (selezionato) - Quando un oggetto viene selezionato, prende
+# questi attributi.
+#
+# Dati questi stati, &egrave; possibile assegnare gli attributi dei widget in
+# ognuno di questi stati usando le seguenti direttive.
+#
+# fg - Assegna il colore di primo piano di un widget.
+# bg - Assegna il colore di sfondo di un widget.
+# bg_pixmap - Inserisce nello sfondo di un widget una pixmap.
+# font - Sceglie il font da usarsi con il dato widget.
+#
+
+# Questo &egrave; uno stile chiamato "button". Il nome non &egrave; veramente importante,
+# in quanto viene assegnato ai veri widget alla fine del file.
+
+style "window"
+{
+ # Questo inserisce nella spaziatura attorno alla finestra la pixmap
+ # specificata.
+ #bg_pixmap[<STATE>] = "<pixmap filename>"
+ bg_pixmap[NORMAL] = "warning.xpm"
+}
+
+style "scale"
+{
+ # Mette il colore di primo piano (il colore del font) a rosso nello
+ # stato "NORMAL".
+
+ fg[NORMAL] = { 1.0, 0, 0 }
+
+ # Inserisce nello sfondo del gadget la stessa pixmap usata dal suo genitore.
+ bg_pixmap[NORMAL] = "<parent>"
+}
+
+style "button"
+{
+ # Questo mostra tutti i possibili stati per un bottone. L'unico che
+ # non &egrave; applicabile &egrave; lo stato "SELECTED".
+
+ fg[PRELIGHT] = { 0, 1.0, 1.0 }
+ bg[PRELIGHT] = { 0, 0, 1.0 }
+ bg[ACTIVE] = { 1.0, 0, 0 }
+ fg[ACTIVE] = { 0, 1.0, 0 }
+ bg[NORMAL] = { 1.0, 1.0, 0 }
+ fg[NORMAL] = { .99, 0, .99 }
+ bg[INSENSITIVE] = { 1.0, 1.0, 1.0 }
+ fg[INSENSITIVE] = { 1.0, 0, 1.0 }
+}
+
+# In questi esempio ereditiamo gli attributi dello stile "button" e poi
+# alteriamo il font e il colore di sfondo quando evidenziato per creare
+# un nuovo stile "main_button".
+
+style "main_button" = "button"
+{
+ font = "-adobe-helvetica-medium-r-normal--*-100-*-*-*-*-*-*"
+ bg[PRELIGHT] = { 0.75, 0, 0 }
+}
+
+style "toggle_button" = "button"
+{
+ fg[NORMAL] = { 1.0, 0, 0 }
+ fg[ACTIVE] = { 1.0, 0, 0 }
+
+ # Questo seleziona come pixmap di sfondo per il toggle_button quella del
+ # suo widget genitore (definita nell'applicazione).
+ bg_pixmap[NORMAL] = "<parent>"
+}
+
+style "text"
+{
+ bg_pixmap[NORMAL] = "marble.xpm"
+ fg[NORMAL] = { 1.0, 1.0, 1.0 }
+}
+
+style "ruler"
+{
+ font = "-adobe-helvetica-medium-r-normal--*-80-*-*-*-*-*-*"
+}
+
+# pixmap_path "~/.pixmaps"
+
+# Queste assegnano ai tipi di widget gli stili definiti prima.
+# I tipi di widget sono elencati nella gerarchia delle classi, ma probabilmente
+# dovrebbero essere elencati in questo documento come riferimento per l'utente.
+
+widget_class "GtkWindow" style "window"
+widget_class "GtkDialog" style "window"
+widget_class "GtkFileSelection" style "window"
+widget_class "*Gtk*Scale" style "scale"
+widget_class "*GtkCheckButton*" style "toggle_button"
+widget_class "*GtkRadioButton*" style "toggle_button"
+widget_class "*GtkButton*" style "button"
+widget_class "*Ruler" style "ruler"
+widget_class "*GtkText" style "text"
+
+# Questo assegna lo stile main_button a tutti i bottoni che sono figli della
+# "main window" (finestra principale). Questi devono essere documenati per
+# potersene avvantaggiare.
+widget "main window.*GtkButton*" style "main_button"
+</verb></tscreen>
+
+
+
+<sect>Scrivere un proprio Widget
+
+<p>
+<sect1> Panoramica
+<p>
+Anche se la distribuzione GTK contiene molto tipi di widget che possono
+coprire molte necessit&agrave; basilari, pu&ograve; essere necessario costruirsi
+un proprio widget. GTK usa molto l'ereditariet&agrave; tra i vari
+widget e, di solito, vi &egrave; un widget che si avvicina a quello che ti
+servirebbe, ed &egrave; spesso possibile creare un nuovo widget con poche linee
+di codice. Ma prima di iniziare il lavoro su un nuovo widget, vediamo
+se qualcuno non lo ha gi&agrave; creato. Questo eviter&agrave; un duplicazione
+di lavoro e far&agrave; s&igrave; che i widget non-GTK puri siano minimi, cos&igrave; da
+aiutare sia chi crea il codice che chi l'interfaccia per applicazioni GTK
+molto grosse. D'altra parte, quando hai finito di scrivere un widget,
+annuncialo a tutto il mondo cos&igrave; che le altre persone ne possano
+beneficiare. Il miglioro modo dove farlo &egrave; la <tt>gtk-list</tt>.
+
+<sect1> L'anatomia di un widget
+
+<p>
+Per creare un nuovo widget &egrave; importante aver capito come gli ogetti
+di GTK lavorano. Questa sezione &egrave; solo una breve spiegazione. Guarda la
+documentazione di riferimento per maggiori dettagli.
+
+<p>
+I widget GTK sono implementati in un modo orientato agli oggetti,
+anche se usando il C standard. Questo aumenta notevolmente la portabilit&agrave;
+e la stabilit&agrave;, specialmente per le correnti generazioni di compilatori C++;
+comunque questo significa che chi scrive un widget deve fare attenzione
+ad alcuni dettagli di implementazione. L'informazione comune a tutte le
+istanze di una classe di widget (ad esempio: a tutti i bottoni) &egrave; memorizzata
+<em>class structure</em>. C'e' solamente una copia di questo in cui
+sono memorizzate le informazioni riguardanti i segnali della classe
+(assomiglia ad una funzione virtuale in C). Per supportare l'ereditariet&agrave;
+il primo campo della struttura di una classe deve essere una copia della
+struttura della classe genitore. La dichiarazione della struttura della
+classe GtkButton &egrave;:
+
+<tscreen><verb>
+struct _GtkButtonClass
+{
+ GtkContainerClass parent_class;
+
+ void (* pressed) (GtkButton *button);
+ void (* released) (GtkButton *button);
+ void (* clicked) (GtkButton *button);
+ void (* enter) (GtkButton *button);
+ void (* leave) (GtkButton *button);
+};
+</verb></tscreen>
+
+<p>
+Quando un bottone viene trattato come un contenitore (ad esempio quando viene
+ridimensionato) si pu&ograve; fare il cast della struttura della sua classe con la
+GtkContainerClass, e usare i campi rilevanti per gestire i segnali.
+
+<p>
+C'&egrave; anche una struttura per ogni widget che viene creata
+ad ogni istanza. Questa struttura ha campi per
+memorizzare le informazioni che sono differenti per ogni volta che il widget
+viene istanziato. Chiameremo questa struttura la <em> struttura
+oggetto</em>. Per la classe Bottone, questa ha l'aspetto:
+
+<tscreen><verb>
+struct _GtkButton
+{
+ GtkContainer container;
+
+ GtkWidget *child;
+
+ guint in_button : 1;
+ guint button_down : 1;
+};
+</verb></tscreen>
+
+<p>
+Si noti che, similmente alla struttura della classe, il primo campo
+&egrave; la struttura dell'oggetto della classe madre, cos&igrave; che, se necessario, si pu&ograve; fare il
+cast di questa struttura con quella dell'oggetto della classe madre.
+
+<sect1> Creare un Widget composto
+
+<sect2> Introduzione
+
+<p>
+Un tipo di widget a cui potreste essere interessati &egrave; un widget che
+&egrave; semplicemnte un aggregato di altri widget GTK. Questo tipo di
+widget non fa nulla che non possa essere fatto creando un nuovo
+widget, ma fornisce un modo conveniente per inscatolare elementi
+dell'interfaccia utente per poi riutilizzarli.
+I widget FileSelection e ColorSelection della ditribuzione standard
+sono esempi di questo tipo di widget.
+
+<p>
+Il widget di esempio che creeremo in questo capitolo &egrave; il
+Tictactoe, un vettore 3x3 di bottoni a commutazione il quale emette
+un segnale quando tutti e 3 i bottoni di una riga, colonna o di una
+diagonale sono premuti.
+
+<sect2> Scegliere la classe madre
+
+<p>
+La classe madre per un widget composto e' tipicamente la classe
+contenitrice che racchiude tutti gli elementi del widget composto.
+Per esempio, la classe madre del widget FileSelection &egrave; la classe
+Dialog. Visto che i nostri bottoni sono inseriti in una tabella, &egrave;
+naturale pensare che la nostra classe madre possa essere la GtkTable.
+Sfortunatamente, cos&igrave; non &egrave;. La creazione di un widget &egrave; diviso
+tra 2 funzioni : la funzione <tt/WIDGETNAME_new()/ che viene invocata
+dall'utente, e la funzione <tt/WIDGETNAME_init()/ che ha il compito
+principale di inizializzare il widget che &egrave; indipendente dai valori
+passati alla funzione <tt/_new()/. Widget figli o discendenti possono
+chiamare, solamente, la funzione del loro widget genitore.
+Ma questa divisione del lavoro non funziona bene per la tabella, la
+quale, quando creata, necessita di conoscere il numero di righe e
+colonne che la comporr&agrave;. A meno che non vogliamo duplicare molte delle
+fuinzionalit&agrave; della <tt/gtk_table_new()/ nel nostro widget
+Tictactoe, faremmo meglio a evitare di derivarlo dalla GtkTable. Per questa
+ragione lo deriviamo invece da GtkVBox, e uniamo la nostra tabella
+dentro il VBox.
+
+<sect2> Il File Header
+
+<p>
+Ogni classe di widget ha un file header il quale dichiara l'oggetto e la
+struttura della classe del widget, comprese le funzioni pubbliche.
+Per prevenire duplicati di definizioni, noi includiamo l'intero file header fra:
+
+<tscreen><verb>
+#ifndef __TICTACTOE_H__
+#define __TICTACTOE_H__
+.
+.
+.
+#endif /* __TICTACTOE_H__ */
+</verb></tscreen>
+
+E per far felici i programmi in C++ che includono il nostro file header, in:
+
+<tscreen><verb>
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+.
+.
+.
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+</verb></tscreen>
+
+Insieme alle funzioni e alle strutture, dichiariamo tre macro
+standard nel nostro file header, <tt/TICTACTOE(obj)/,
+<tt/TICTACTOE_CLASS(klass)/, e <tt/IS_TICTACTOE(obj)/, i quali rispettivamente
+fanno il cast di un puntatore ad un puntatore ad un ogetto od ad una struttura
+di classe, e guarda se un oggetto &egrave; un widget Tictactoe.
+
+
+Qui vi &egrave; il file header completo:
+
+<tscreen><verb>
+
+#ifndef __TICTACTOE_H__
+#define __TICTACTOE_H__
+
+#include <gdk/gdk.h>
+#include <gtk/gtkvbox.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define TICTACTOE(obj) GTK_CHECK_CAST (obj, tictactoe_get_type (), Tictactoe)
+#define TICTACTOE_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, tictactoe_get_type (), TictactoeClass)
+#define IS_TICTACTOE(obj) GTK_CHECK_TYPE (obj, tictactoe_get_type ())
+
+
+typedef struct _Tictactoe Tictactoe;
+typedef struct _TictactoeClass TictactoeClass;
+
+struct _Tictactoe
+{
+ GtkVBox vbox;
+
+ GtkWidget *buttons[3][3];
+};
+
+struct _TictactoeClass
+{
+ GtkVBoxClass parent_class;
+
+ void (* tictactoe) (Tictactoe *ttt);
+};
+
+guint tictactoe_get_type (void);
+GtkWidget* tictactoe_new (void);
+void tictactoe_clear (Tictactoe *ttt);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __TICTACTOE_H__ */
+
+</verb></tscreen>
+
+<sect2> La funzione <tt/_get_type()/
+
+<p>
+Continuiamo ora con l'implementazione del nostro widget. Una funzione
+basilare di ogni widget &egrave; la funzione <tt/WIDGETNAME_get_type()/.
+Questa funzione, quando chiamata la prima volta, comunica a GTK la classe
+del widget, e ottiene un identificativo univoco per la classe del
+widget. Chiamate successive restituiscono semplicemente l'identificativo.
+
+<tscreen><verb>
+guint
+tictactoe_get_type ()
+{
+ static guint ttt_type = 0;
+
+ if (!ttt_type)
+ {
+ GtkTypeInfo ttt_info =
+ {
+ "Tictactoe",
+ sizeof (Tictactoe),
+ sizeof (TictactoeClass),
+ (GtkClassInitFunc) tictactoe_class_init,
+ (GtkObjectInitFunc) tictactoe_init,
+ (GtkArgFunc) NULL,
+ };
+
+ ttt_type = gtk_type_unique (gtk_vbox_get_type (), &amp;ttt_info);
+ }
+
+ return ttt_type;
+}
+</verb></tscreen>
+
+<p>
+La struttura GtkTypeInfo ha la seguente definizione:
+
+<tscreen><verb>
+struct _GtkTypeInfo
+{
+ gchar *type_name;
+ guint object_size;
+ guint class_size;
+ GtkClassInitFunc class_init_func;
+ GtkObjectInitFunc object_init_func;
+ GtkArgFunc arg_func;
+};
+</verb></tscreen>
+
+<p>
+I campi di questa struttura sono abbastanza auto-esplicativi.
+Ignoreremo, per ora, il campo <tt/arg_func/: ha un ruolo importante, ma
+non ancora largamente implementato, nel permettere ai linguaggi interpretati
+di settare convenientemente le opzioni del widget.
+Una volta che il GTK ha completato correttamente una copia di questa
+struttura, sa come creare un oggetto di un particolare widget.
+
+<sect2> La funzione <tt/_class_init()/
+<p>
+La funzione <tt/WIDGETNAME_class_init()/ inizialiazza i campi della
+struttura della classe del widget, e setta ogni segnale della classe.
+Per il nostro widget Tictactoe ha il seguente aspetto:
+
+<tscreen><verb>
+
+enum {
+ TICTACTOE_SIGNAL,
+ LAST_SIGNAL
+};
+
+static gint tictactoe_signals[LAST_SIGNAL] = { 0 };
+
+static void
+tictactoe_class_init (TictactoeClass *class)
+{
+ GtkObjectClass *object_class;
+
+ object_class = (GtkObjectClass*) class;
+
+ tictactoe_signals[TICTACTOE_SIGNAL] = gtk_signal_new ("tictactoe",
+ GTK_RUN_FIRST,
+ object_class->type,
+ GTK_SIGNAL_OFFSET (TictactoeClass, tictactoe),
+ gtk_signal_default_marshaller, GTK_ARG_NONE, 0);
+
+
+ gtk_object_class_add_signals (object_class, tictactoe_signals, LAST_SIGNAL);
+
+ class->tictactoe = NULL;
+}
+</verb></tscreen>
+
+<p>
+Il nostro widget ha semplicemente il segnale ``tictactoe'' che &egrave;
+invocato quando una riga, colonna o diagonale &egrave; completamente premuta.
+Non tutti i widget composti necessitano di segnali, quindi se stai
+leggendo questo per la prima volta, puoi anche saltare alla prossima sezione,
+dal momento che a questo punto le cose diventano un po' complicate.
+
+La funzione:
+<tscreen><verb>
+gint gtk_signal_new (gchar *name,
+ GtkSignalRunType run_type,
+ gint object_type,
+ gint function_offset,
+ GtkSignalMarshaller marshaller,
+ GtkArgType return_val,
+ gint nparams,
+ ...);
+</verb></tscreen>
+
+crea un nuovo segnale. I parametri sono:
+
+<itemize>
+<item> <tt/name/: Il nome del segnale.
+<item> <tt/run_type/: Se il segstore predefinito viene eseguito prima o dopo
+di quello dell'utente. Di norma questo sar&agrave; <tt/GTK_RUN_FIRST/, o <tt/GTK_RUN_LAST/,
+anche se ci sono altre possibilit&agrave;.
+<item> <tt/object_type/: l'identificativo dell'oggetto a cui questo segnale si
+riferisce. Esso sar&agrave; anche applicato agli oggetti discendenti.
+<item> <tt/function_offset/: L'offset nella struttura della classe di un
+puntatore al gestore predefinito.
+<item> <tt/marshaller/: una funzione che &egrave; usata per invocare il gestore
+del segnale. Per gestori di segnali che non hanno argomenti oltre
+all'oggetto che emette il segnale e i dati dell'utente, possiamo usare
+la funzione predefinita <tt/gtk_signal_default_marshaller/
+<item> <tt/return_val/: Il tipo del valore di ritorno.
+<item> <tt/nparams/: Il numero di parametri del gestore di segnali (oltre
+ai due predefiniti menzionati sopra)
+<item> <tt/.../: i tipi dei parametri
+</itemize>
+
+Quando si specificano i tipi, si usa l'enumerazione <tt/GtkArgType/:
+
+<tscreen><verb>
+typedef enum
+{
+ GTK_ARG_INVALID,
+ GTK_ARG_NONE,
+ GTK_ARG_CHAR,
+ GTK_ARG_SHORT,
+ GTK_ARG_INT,
+ GTK_ARG_LONG,
+ GTK_ARG_POINTER,
+ GTK_ARG_OBJECT,
+ GTK_ARG_FUNCTION,
+ GTK_ARG_SIGNAL
+} GtkArgType;
+</verb></tscreen>
+
+<p>
+<tt/gtk_signal_new()/ restituisce un identificatore unico intero per il segnale,
+che memorizziamo nel vettore <tt/tictactoe_signals/, che
+indicizzeremo usando una enumerazione. (Convenzionalmente, gli elementi dell'enumerazione
+sono i nomi dei segnali, in maiuscolo,
+ma qui ci potrebbe essere un conflitto con la macro <tt/TICTACTOE()/,
+quindi l'abbiamo chiamato <tt/TICTACTOE_SIGNAL/
+
+Dopo aver creato un nostro segnale, abbiamo bisogno di dire a GTK
+di associare il nostro segnale alla classe Tictactoe. Lo facciamo
+invocando <tt/gtk_object_class_add_signals()/. Settiamo quindi a NULL
+il puntatore che punta al gestore predefinito per il segnale
+``tictactoe'' a NULL, indicando che non ci sono azioni predefinite.
+
+<sect2> La funzione <tt/_init()/
+
+<p>
+
+Ogni classe di Widget necessita anche di una funzione per inizializzare
+la struttura dell'oggetto. Usualmente questa funzione ha il ruolo abbastanza
+limitato di assegnare ai campi della struttura i valori predefiniti.
+Per widget composti, comunque, questa funzione crea, anche,
+i widget componenti del widget composto.
+
+<tscreen><verb>
+
+static void
+tictactoe_init (Tictactoe *ttt)
+{
+ GtkWidget *table;
+ gint i,j;
+
+ table = gtk_table_new (3, 3, TRUE);
+ gtk_container_add (GTK_CONTAINER(ttt), table);
+ gtk_widget_show (table);
+
+ for (i=0;i<3; i++)
+ for (j=0;j<3; j++)
+ {
+ ttt->buttons[i][j] = gtk_toggle_button_new ();
+ gtk_table_attach_defaults (GTK_TABLE(table), ttt->buttons[i][j],
+ i, i+1, j, j+1);
+ gtk_signal_connect (GTK_OBJECT (ttt->buttons[i][j]), "toggled",
+ GTK_SIGNAL_FUNC (tictactoe_toggle), ttt);
+ gtk_widget_set_usize (ttt->buttons[i][j], 20, 20);
+ gtk_widget_show (ttt->buttons[i][j]);
+ }
+}
+</verb></tscreen>
+
+<sect2> E il resto...
+
+<p>
+
+C'&egrave; un'altra funzione che ogni widget (eccetto i Widget di base come
+GtkBin che non possono essere instanziati) deve avere : la funzione
+che l'utente invoca per creare un oggetto di quel tipo. Questa &egrave;
+convenzionalmente chiamata <tt/WIDGETNAME_new()/. In alcuni widget,
+non nel caso del nostro Tictactoe, questa funzione richiede degli
+argomenti, e fa alcune operazioni basandosi su di essi. Le altre
+due funzioni sono specifiche del widget Tictactoe.
+
+<p>
+<tt/tictactoe_clear()/ &egrave; una funzione pubblica che resetta tutti i
+bottoni, nel widget, allo stato iniziale (non premuto). Notate l'uso
+di <tt/gtk_signal_handler_block_by_data()/ per impedire che il nostro
+gestore dei segnali venga attivato quando non ce n'&egrave; bisogno.
+
+<p>
+<tt/tictactoe_toggle()/ &egrave; il gestore del segnale che viene invocato
+quando l'utente preme il bottone. Esso guarda se vi &egrave;
+qualche combinazione vincente che coinvolge i bottoni premuti, e nel
+caso ci fosse, emette il segnale ``tictactoe''.
+
+<tscreen><verb>
+GtkWidget*
+tictactoe_new ()
+{
+ return GTK_WIDGET ( gtk_type_new (tictactoe_get_type ()));
+}
+
+void
+tictactoe_clear (Tictactoe *ttt)
+{
+ int i,j;
+
+ for (i=0;i<3;i++)
+ for (j=0;j<3;j++)
+ {
+ gtk_signal_handler_block_by_data (GTK_OBJECT(ttt->buttons[i][j]), ttt);
+ gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (ttt->buttons[i][j]),
+ FALSE);
+ gtk_signal_handler_unblock_by_data (GTK_OBJECT(ttt->buttons[i][j]), ttt);
+ }
+}
+
+static void
+tictactoe_toggle (GtkWidget *widget, Tictactoe *ttt)
+{
+ int i,k;
+
+ static int rwins[8][3] = { { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 },
+ { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 },
+ { 0, 1, 2 }, { 0, 1, 2 } };
+ static int cwins[8][3] = { { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 },
+ { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 },
+ { 0, 1, 2 }, { 2, 1, 0 } };
+
+ int success, found;
+
+ for (k=0; k<8; k++)
+ {
+ success = TRUE;
+ found = FALSE;
+
+ for (i=0;i<3;i++)
+ {
+ success = success &amp;&amp;
+ GTK_TOGGLE_BUTTON(ttt->buttons[rwins[k][i]][cwins[k][i]])->active;
+ found = found ||
+ ttt->buttons[rwins[k][i]][cwins[k][i]] == widget;
+ }
+
+ if (success &amp;&amp; found)
+ {
+ gtk_signal_emit (GTK_OBJECT (ttt),
+ tictactoe_signals[TICTACTOE_SIGNAL]);
+ break;
+ }
+ }
+}
+</verb></tscreen>
+
+<p>
+
+E finalmente un programma di esempio che usa il nostro widget
+Tictactoe:
+
+<tscreen><verb>
+#include <gtk/gtk.h>
+#include "tictactoe.h"
+
+/* Invocato quando una riga, colonna o diagonale e' completata. */
+void
+win (GtkWidget *widget, gpointer data)
+{
+ g_print ("Yay!\n");
+ tictactoe_clear (TICTACTOE (widget));
+}
+
+int
+main (int argc, char *argv[])
+{
+ GtkWidget *window;
+ GtkWidget *ttt;
+
+ gtk_init (&amp;argc, &amp;argv);
+
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+
+ gtk_window_set_title (GTK_WINDOW (window), "Aspect Frame");
+
+ gtk_signal_connect (GTK_OBJECT (window), "destroy",
+ GTK_SIGNAL_FUNC (gtk_exit), NULL);
+
+ gtk_container_border_width (GTK_CONTAINER (window), 10);
+
+ /* Crea un nuovo widget Tictactoe. */
+ ttt = tictactoe_new ();
+ gtk_container_add (GTK_CONTAINER (window), ttt);
+ gtk_widget_show (ttt);
+
+ /* E gli aggancia il segnale "tictactoe" */
+ gtk_signal_connect (GTK_OBJECT (ttt), "tictactoe",
+ GTK_SIGNAL_FUNC (win), NULL);
+
+ gtk_widget_show (window);
+
+ gtk_main ();
+
+ return 0;
+}
+
+</verb></tscreen>
+
+
+<sect1> Creare un widget a partire da zero
+
+<sect2> Introduzione
+
+<p>
+
+In questa sezione impareremo meglio come i widget si mostrano sullo schermo
+e interagiscono con gli eventi. Come esempio, creeremo
+un widget di quadrante analogico con un puntatore che l'utente
+pu&ograve; trascinare per assegnare il valore.
+
+<sect2> Mostrare un widget sullo schermo
+
+<p>
+Ci sono alcuni passi che sono necessari nella visualizzazione sullo
+schermo. Dopo che il widget &egrave; stato creato con una chiamata a
+<tt/WIDGETNAME_new()/, sono necessarie alcune altre funzioni:
+
+<itemize>
+<item> <tt/WIDGETNAME_realize()/ &egrave; responsabile della creazione di
+una finestra X per il widget se ne ha una.
+<item> <tt/WIDGETNAME_map()/ &egrave; invocata dopo che l'utente ha
+chiamato <tt/gtk_widget_show()/. E' responsabile di vedere se il
+widget &egrave; attualmente disegnato sullo schermo (<em/mappato/). Per
+una classe contenitore, essa deve anche creare chiamate alle
+funzioni <tt/map()/> per ogni widget figlio.
+<item> <tt/WIDGETNAME_draw()/ &egrave; invocata quando
+<tt/gtk_widget_draw()/ viene chiamata per il widget o per uno dei suoi
+predecessori. Esso fa s&igrave; che l'attuale chiamata alla
+funzione di disegno del widget disegni il widget sullo schermo.
+Per la classe contenitore, questa funzione deve eseguire le
+chiamate alla funzioni <tt/gtk_widget_draw()/ di ogni suo widget
+figlio.
+<item> <tt/WIDGETNAME_expose()/ &egrave; un gestore per l'evento di esposizione
+per il widget. Esso crea le chiamate necessarie alle funzioni di disegno
+per disegnare la porzione che si &egrave; resa visibile. Per le classi
+contenitore, questa funzione deve generare gli eventi di ``expose'' per
+tutti i widget figli che non hanno una propria finestra (se essi hanno
+una loro finestra, sar&agrave; X che generer&agrave; i necessari eventi di expose).
+</itemize>
+
+<p>
+Potete notare che le ultime due funzioni sono molto simili, ognuna &egrave;
+responsabile per il disegno del widget sullo schermo. Infatti molti
+tipi di widget non sanno relamente la differenza tra le due.
+La funzione di predefinita <tt/draw()/ nella classe widget, semplicemente
+genera un sintetico evento di ``expose'' per l'area da ridisegnare.
+Comunque, alcuni tipi di widget possono risparmiare tempo distinguendo
+le due funzioni. Per esempio, se un widget ha piu' finestre X, allora
+visto che l'evento ``expose'' identifica solo la finestra esposta,
+esso pu&ograve; ridisegnare solo la finestra interessata, cosa che non &egrave;
+possibile per chiamate a <tt/draw()/.
+
+<p>
+I widget contenitori, anche se essi non farebbero differenze,
+non possono semplicemente usare la funzione <tt/draw()/ perch&egrave; per i
+loro widget figli la differenza potrebbere essere importante. Comunque,
+sarebbe uno spreco duplicare il codice di disegno nelle due
+funzioni. La convenzione &egrave; che questi widget abbiano una funzione
+chiamata <tt/WIDGETNAME_paint()/ che disegna il widget, che &egrave; poi
+chiamata dalle funzioni <tt/draw()/ e <tt/expose()/
+
+<p>
+Nell'approccio del nostro esempio, visto che il widget, ha
+una sola finestra, possiamo utilizzare il modo piu' semplice
+ed usare la funzione predefinita <tt/draw()/ e implementare
+solamente la funzione <tt/expose()/.
+
+<sect2> Le origini del widget Dial
+
+<p>
+Come tutti gli animali terresti sono semplicemente varianti del primo
+amfibio, i widget Gtk tendono ad essere varianti di altri widget, precedentemente
+scritti. Cos&igrave;, anche se questa sezione &egrave; intitolata ``Creare
+un widget a partire da zero", il nostro widget inizia in realt&agrave; con il codice
+sorgente del widget Range. Questo &egrave; stato preso come punto d'inizio
+perche' sarebbe carino se il nostro widget avesse la
+stessa interfaccia del widget Scale il quale &egrave; semplicemente una
+specializzazione del widget Range. Cos&igrave;, sebbene il codice sorgente e'
+presentato sotto in forma definitiva, non si deve pensare che sia stato
+scritto <em>deus ex machina</em> in questo modo. Se poi non avete familiarit&agrave;
+con il funzionamento del widget Scale dal punto di vista di chi scrive
+un'applicazione, potrebbe essere una buona idea guardare indietro prima
+di continuare.
+
+<sect2> Le basi
+
+<p>
+Una parte del nostro widget potrebbe essere simile
+al widget Tictactoe. In primo luogo, abbiamo il file header:
+
+<tscreen><verb>
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __GTK_DIAL_H__
+#define __GTK_DIAL_H__
+
+#include <gdk/gdk.h>
+#include <gtk/gtkadjustment.h>
+#include <gtk/gtkwidget.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+#define GTK_DIAL(obj) GTK_CHECK_CAST (obj, gtk_dial_get_type (), GtkDial)
+#define GTK_DIAL_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_dial_get_type (), GtkDialClass)
+#define GTK_IS_DIAL(obj) GTK_CHECK_TYPE (obj, gtk_dial_get_type ())
+
+
+typedef struct _GtkDial GtkDial;
+typedef struct _GtkDialClass GtkDialClass;
+
+struct _GtkDial
+{
+ GtkWidget widget;
+
+ /* Politica di update (GTK_UPDATE_[CONTINUOUS/DELAYED/DISCONTINUOUS]) */
+ guint policy : 2;
+
+ /* Bottone correntemente premuto o 0 altrimenti */
+ guint8 button;
+
+ /* Dimensione della componente Dial. */
+ gint radius;
+ gint pointer_width;
+
+ /* ID del timer di update, o 0 altrimenti */
+ guint32 timer;
+
+ /* Angolo corrente. */
+ gfloat angle;
+
+ /* Vecchi valori dell'aggiustamento cos&igrave; sappiamo quando
+ * qualcosa cambia */
+ gfloat old_value;
+ gfloat old_lower;
+ gfloat old_upper;
+
+ /* L'oggetto adjustament che memorizza i dati per questo dial */
+ GtkAdjustment *adjustment;
+};
+
+struct _GtkDialClass
+{
+ GtkWidgetClass parent_class;
+};
+
+
+GtkWidget* gtk_dial_new (GtkAdjustment *adjustment);
+guint gtk_dial_get_type (void);
+GtkAdjustment* gtk_dial_get_adjustment (GtkDial *dial);
+void gtk_dial_set_update_policy (GtkDial *dial,
+ GtkUpdateType policy);
+
+void gtk_dial_set_adjustment (GtkDial *dial,
+ GtkAdjustment *adjustment);
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GTK_DIAL_H__ */
+
+</verb></tscreen>
+
+Essendoci pi&ugrave; cose da fare con questo widget, rispetto al precedente,
+abbiamo pi&ugrave; cambi nella struttura dati, ma le altre cose sono
+abbastamza simili.
+
+<p>
+
+Dopo aver incluso i file di header e aver dichiarato alcune costanti,
+dobbiamo fornire alcune funzioni circa il widget e la sua
+inizializzazione.
+
+<tscreen><verb>
+#include <math.h>
+#include <stdio.h>
+#include <gtk/gtkmain.h>
+#include <gtk/gtksignal.h>
+
+#include "gtkdial.h"
+
+#define SCROLL_DELAY_LENGTH 300
+#define DIAL_DEFAULT_SIZE 100
+
+/* Dichiarazioni di funzioni successive */
+
+[ omesse per salvare spazio ]
+
+/* variabili locali. */
+
+static GtkWidgetClass *parent_class = NULL;
+
+guint
+gtk_dial_get_type ()
+{
+ static guint dial_type = 0;
+
+ if (!dial_type)
+ {
+ GtkTypeInfo dial_info =
+ {
+ "GtkDial",
+ sizeof (GtkDial),
+ sizeof (GtkDialClass),
+ (GtkClassInitFunc) gtk_dial_class_init,
+ (GtkObjectInitFunc) gtk_dial_init,
+ (GtkArgFunc) NULL,
+ };
+
+ dial_type = gtk_type_unique (gtk_widget_get_type (), &amp;dial_info);
+ }
+
+ return dial_type;
+}
+
+static void
+gtk_dial_class_init (GtkDialClass *class)
+{
+ GtkObjectClass *object_class;
+ GtkWidgetClass *widget_class;
+
+ object_class = (GtkObjectClass*) class;
+ widget_class = (GtkWidgetClass*) class;
+
+ parent_class = gtk_type_class (gtk_widget_get_type ());
+
+ object_class->destroy = gtk_dial_destroy;
+
+ widget_class->realize = gtk_dial_realize;
+ widget_class->expose_event = gtk_dial_expose;
+ widget_class->size_request = gtk_dial_size_request;
+ widget_class->size_allocate = gtk_dial_size_allocate;
+ widget_class->button_press_event = gtk_dial_button_press;
+ widget_class->button_release_event = gtk_dial_button_release;
+ widget_class->motion_notify_event = gtk_dial_motion_notify;
+}
+
+static void
+gtk_dial_init (GtkDial *dial)
+{
+ dial->button = 0;
+ dial->policy = GTK_UPDATE_CONTINUOUS;
+ dial->timer = 0;
+ dial->radius = 0;
+ dial->pointer_width = 0;
+ dial->angle = 0.0;
+ dial->old_value = 0.0;
+ dial->old_lower = 0.0;
+ dial->old_upper = 0.0;
+ dial->adjustment = NULL;
+}
+
+GtkWidget*
+gtk_dial_new (GtkAdjustment *adjustment)
+{
+ GtkDial *dial;
+
+ dial = gtk_type_new (gtk_dial_get_type ());
+
+ if (!adjustment)
+ adjustment = (GtkAdjustment*) gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
+
+ gtk_dial_set_adjustment (dial, adjustment);
+
+ return GTK_WIDGET (dial);
+}
+
+static void
+gtk_dial_destroy (GtkObject *object)
+{
+ GtkDial *dial;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GTK_IS_DIAL (object));
+
+ dial = GTK_DIAL (object);
+
+ if (dial->adjustment)
+ gtk_object_unref (GTK_OBJECT (dial->adjustment));
+
+ if (GTK_OBJECT_CLASS (parent_class)->destroy)
+ (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
+}
+</verb></tscreen>
+
+Notate che questa funzione <tt/init()/ fa meno rispetto all'analoga del
+widget Tictactoe, essendo questo un widget non composto, e la
+funzione <tt/new()/ fa di pi&ugrave;, essendoci un argomento. Inoltre,
+notate che quando memorizziamo un puntatore all'oggetto Adjustment,
+incrementiamo il conteggio dei suoi riferimenti(e corrispondentemente
+lo decrementato quando non lo usiamo pi&ugrave;) cos&igrave; che GTK pu&ograve; tener traccia di
+quando &egrave; possibile distruggerlo senza causare guai.
+
+<p>
+Inoltre, ci sono alcune funzioni per manipolare le opzioni del widget:
+
+<tscreen><verb>
+GtkAdjustment*
+gtk_dial_get_adjustment (GtkDial *dial)
+{
+ g_return_val_if_fail (dial != NULL, NULL);
+ g_return_val_if_fail (GTK_IS_DIAL (dial), NULL);
+
+ return dial->adjustment;
+}
+
+void
+gtk_dial_set_update_policy (GtkDial *dial,
+ GtkUpdateType policy)
+{
+ g_return_if_fail (dial != NULL);
+ g_return_if_fail (GTK_IS_DIAL (dial));
+
+ dial->policy = policy;
+}
+
+void
+gtk_dial_set_adjustment (GtkDial *dial,
+ GtkAdjustment *adjustment)
+{
+ g_return_if_fail (dial != NULL);
+ g_return_if_fail (GTK_IS_DIAL (dial));
+
+ if (dial->adjustment)
+ {
+ gtk_signal_disconnect_by_data (GTK_OBJECT (dial->adjustment), (gpointer) dial);
+ gtk_object_unref (GTK_OBJECT (dial->adjustment));
+ }
+
+ dial->adjustment = adjustment;
+ gtk_object_ref (GTK_OBJECT (dial->adjustment));
+
+ gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
+ (GtkSignalFunc) gtk_dial_adjustment_changed,
+ (gpointer) dial);
+ gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
+ (GtkSignalFunc) gtk_dial_adjustment_value_changed,
+ (gpointer) dial);
+
+ dial->old_value = adjustment->value;
+ dial->old_lower = adjustment->lower;
+ dial->old_upper = adjustment->upper;
+
+ gtk_dial_update (dial);
+}
+</verb></tscreen>
+
+<sect2> <tt/gtk_dial_realize()/
+
+<p>
+Abbiamo ora raggiunto alcuni nuovi tipi di funzione. In primo luogo,
+abbiamo una funzione che crea la finestra di X. Noterete che viene
+passata alla funzione <tt/gdk_window_new()/ una maschera che
+specifica quali campi della struttura GdkWindowAttr non sono vuoti
+(ai rimanenti campi pu&ograve; essere dato il valore predefinito). Anche
+il modo con cui la maschera degli eventi del widget creata non &egrave;
+complicato. Chiameremo <tt/gtk_widget_get_events()/ per sapere la
+maschera degli eventi che l'utente ha specificato per questo widget
+(con <tt/gtk_widget_set_events()/) e aggiungeremo gli eventi che ci possono
+interessare.
+
+<p>
+Dopo aver creato la finestra, settiamo lo stile e lo sfondo,
+e creiamo un puntatore al widget nel campo dei dati utente (user data)
+del GdkWindow. Quest'ultimo passo permette a GTK di mandare gli
+eventi della finestra al widget corretto.
+
+<tscreen><verb>
+static void
+gtk_dial_realize (GtkWidget *widget)
+{
+ GtkDial *dial;
+ GdkWindowAttr attributes;
+ gint attributes_mask;
+
+ g_return_if_fail (widget != NULL);
+ g_return_if_fail (GTK_IS_DIAL (widget));
+
+ GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
+ dial = GTK_DIAL (widget);
+
+ attributes.x = widget->allocation.x;
+ attributes.y = widget->allocation.y;
+ attributes.width = widget->allocation.width;
+ attributes.height = widget->allocation.height;
+ attributes.wclass = GDK_INPUT_OUTPUT;
+ attributes.window_type = GDK_WINDOW_CHILD;
+ attributes.event_mask = gtk_widget_get_events (widget) |
+ GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK |
+ GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK |
+ GDK_POINTER_MOTION_HINT_MASK;
+ attributes.visual = gtk_widget_get_visual (widget);
+ attributes.colormap = gtk_widget_get_colormap (widget);
+
+ attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
+ widget->window = gdk_window_new (widget->parent->window, &amp;attributes, attributes_mask);
+
+ widget->style = gtk_style_attach (widget->style, widget->window);
+
+ gdk_window_set_user_data (widget->window, widget);
+
+ gtk_style_set_background (widget->style, widget->window, GTK_STATE_ACTIVE);
+}
+</verb></tscreen>
+
+<sect2> Negoziazione della dimensione
+
+<p>
+Prima di visualizzare per la prima volta la finestra, e se il
+layout della finestra cambia, GTK chiede ad ogni widget, incluso nella
+finestra, la propria dimensione. Questa richiesta &egrave; fatta dalla
+funzione <tt/gtk_dial_size_request()/. Non essendo il nostro widget
+un contenitore, e non avendo dei veri limiti per la propria
+dimensione, restituiamo semplicemnte un valore ragionevole.
+
+<tscreen><verb>
+static void
+gtk_dial_size_request (GtkWidget *widget,
+ GtkRequisition *requisition)
+{
+ requisition->width = DIAL_DEFAULT_SIZE;
+ requisition->height = DIAL_DEFAULT_SIZE;
+}
+</verb></tscreen>
+
+<p>
+Dopo che tutti i widget hanno restituito una dimensione ideale, viene
+calcolata la disposizione della finestra e ad ogni widget figlio &egrave;
+notificata la propria dimensione attuale <!--ndMichel : che pu&ograve; essere diversa
+da quella restitutita con la funzione sopra -->. Usualmente, questo sar&agrave;
+almeno quanto richiesto, ma occasionalmente pu&ograve; essere pi&ugrave; piccolo.
+La notifica della dimensione viene fatta dalla funzione
+ <tt/gtk_dial_size_allocate()/. Notate che questa funzione &egrave; utilizzata
+anche quando la finestra X del widget &egrave; spostata o modificata come
+dimensione.
+
+<tscreen><verb>
+static void
+gtk_dial_size_allocate (GtkWidget *widget,
+ GtkAllocation *allocation)
+{
+ GtkDial *dial;
+
+ g_return_if_fail (widget != NULL);
+ g_return_if_fail (GTK_IS_DIAL (widget));
+ g_return_if_fail (allocation != NULL);
+
+ widget->allocation = *allocation;
+ if (GTK_WIDGET_REALIZED (widget))
+ {
+ dial = GTK_DIAL (widget);
+
+ gdk_window_move_resize (widget->window,
+ allocation->x, allocation->y,
+ allocation->width, allocation->height);
+
+ dial->radius = MAX(allocation->width,allocation->height) * 0.45;
+ dial->pointer_width = dial->radius / 5;
+ }
+}
+</verb></tscreen>.
+
+<sect2> <tt/gtk_dial_expose()/
+
+<p>
+Come menzionato sopra, tutto il lavoro di questo widget viene fatto nella
+gestione dell'evento ``expose''. Non c'&egrave; molto da notare su questo eccetto
+l'uso della funzione <tt/gtk_draw_polygon/ per disegnare il
+puntatore con un'ombreggiatura a tre dimensioni in accordo con il colore
+memorizzato nello stile del wiget.
+
+<tscreen><verb>
+static gint
+gtk_dial_expose (GtkWidget *widget,
+ GdkEventExpose *event)
+{
+ GtkDial *dial;
+ GdkPoint points[3];
+ gdouble s,c;
+ gdouble theta;
+ gint xc, yc;
+ gint tick_length;
+ gint i;
+
+ g_return_val_if_fail (widget != NULL, FALSE);
+ g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
+ g_return_val_if_fail (event != NULL, FALSE);
+
+ if (event->count > 0)
+ return FALSE;
+
+ dial = GTK_DIAL (widget);
+
+ gdk_window_clear_area (widget->window,
+ 0, 0,
+ widget->allocation.width,
+ widget->allocation.height);
+
+ xc = widget->allocation.width/2;
+ yc = widget->allocation.height/2;
+
+ /* Draw ticks */
+
+ for (i=0; i<25; i++)
+ {
+ theta = (i*M_PI/18. - M_PI/6.);
+ s = sin(theta);
+ c = cos(theta);
+
+ tick_length = (i%6 == 0) ? dial->pointer_width : dial->pointer_width/2;
+
+ gdk_draw_line (widget->window,
+ widget->style->fg_gc[widget->state],
+ xc + c*(dial->radius - tick_length),
+ yc - s*(dial->radius - tick_length),
+ xc + c*dial->radius,
+ yc - s*dial->radius);
+ }
+
+ /* Draw pointer */
+
+ s = sin(dial->angle);
+ c = cos(dial->angle);
+
+
+ points[0].x = xc + s*dial->pointer_width/2;
+ points[0].y = yc + c*dial->pointer_width/2;
+ points[1].x = xc + c*dial->radius;
+ points[1].y = yc - s*dial->radius;
+ points[2].x = xc - s*dial->pointer_width/2;
+ points[2].y = yc - c*dial->pointer_width/2;
+
+ gtk_draw_polygon (widget->style,
+ widget->window,
+ GTK_STATE_NORMAL,
+ GTK_SHADOW_OUT,
+ points, 3,
+ TRUE);
+
+ return FALSE;
+}
+</verb></tscreen>
+
+<sect2> Gestore degli eventi
+
+<p>
+
+Il resto del codice del widget manipola vari tipi di eventi, e non
+&egrave; differente da quello che pu&ograve; essere trovato in molte applicazione
+GTK. Due tipi di eventi possono verificarsi: l'utente pu&ograve;
+clickare sul widget con il mouse e trascinare per muovere il puntatore,
+o il valore dell'oggetto Adjustmente pu&ograve; cambiare a causa di alcune
+circostanze esterne.
+
+<p>
+Quando l'utente clicka sul widget, noi vediamo se la pressione
+era veramente vicina al puntatore, e se cos&igrave;, memorizziamo il bottone
+premuto dall'utente con il campo <tt/button/ della struttura del
+widget, e prendiamo tutti gli eventi del mouse con una chiamata alla
+funzione <tt/gtk_grab_add()/. Successivi movimenti del mouse causano il
+ricalcolo dei valori di controllo (fatto dalla funzione
+<tt/gtk_dial_update_mouse/). Dipendentemente dalla politica che abbiamo
+stabilito, gli eventi ``value_changed'' possono essere generati
+istantaneamente (<tt/GTK_UPDATE_CONTINUOUS/), dopo un certo tempo aggiunto
+con la funzione <tt/gtk_timeout_add()/ (<tt/GTK_UPDATE_DELAYED/), o
+solamente quando il bottone del mouse e' rilasciato
+(<tt/GTK_UPDATE_DISCONTINUOUS/).
+
+<tscreen><verb>
+static gint
+gtk_dial_button_press (GtkWidget *widget,
+ GdkEventButton *event)
+{
+ GtkDial *dial;
+ gint dx, dy;
+ double s, c;
+ double d_parallel;
+ double d_perpendicular;
+
+ g_return_val_if_fail (widget != NULL, FALSE);
+ g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
+ g_return_val_if_fail (event != NULL, FALSE);
+
+ dial = GTK_DIAL (widget);
+
+ /* Determina se il bottone premuto era dentro la regione del puntatore:
+ lo facciamo calcolando la distanza parallela e
+ perpendicolare dal punto dove il bottone del mouse e' stato premuto
+ alla linea passante per il puntatore. */
+
+ dx = event->x - widget->allocation.width / 2;
+ dy = widget->allocation.height / 2 - event->y;
+
+ s = sin(dial->angle);
+ c = cos(dial->angle);
+
+ d_parallel = s*dy + c*dx;
+ d_perpendicular = fabs(s*dx - c*dy);
+
+ if (!dial->button &&
+ (d_perpendicular < dial->pointer_width/2) &&
+ (d_parallel > - dial->pointer_width))
+ {
+ gtk_grab_add (widget);
+
+ dial->button = event->button;
+
+ gtk_dial_update_mouse (dial, event->x, event->y);
+ }
+
+ return FALSE;
+}
+
+static gint
+gtk_dial_button_release (GtkWidget *widget,
+ GdkEventButton *event)
+{
+ GtkDial *dial;
+
+ g_return_val_if_fail (widget != NULL, FALSE);
+ g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
+ g_return_val_if_fail (event != NULL, FALSE);
+
+ dial = GTK_DIAL (widget);
+
+ if (dial->button == event->button)
+ {
+ gtk_grab_remove (widget);
+
+ dial->button = 0;
+
+ if (dial->policy == GTK_UPDATE_DELAYED)
+ gtk_timeout_remove (dial->timer);
+
+ if ((dial->policy != GTK_UPDATE_CONTINUOUS) &&
+ (dial->old_value != dial->adjustment->value))
+ gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
+ }
+
+ return FALSE;
+}
+
+static gint
+gtk_dial_motion_notify (GtkWidget *widget,
+ GdkEventMotion *event)
+{
+ GtkDial *dial;
+ GdkModifierType mods;
+ gint x, y, mask;
+
+ g_return_val_if_fail (widget != NULL, FALSE);
+ g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
+ g_return_val_if_fail (event != NULL, FALSE);
+
+ dial = GTK_DIAL (widget);
+
+ if (dial->button != 0)
+ {
+ x = event->x;
+ y = event->y;
+
+ if (event->is_hint || (event->window != widget->window))
+ gdk_window_get_pointer (widget->window, &amp;x, &amp;y, &amp;mods);
+
+ switch (dial->button)
+ {
+ case 1:
+ mask = GDK_BUTTON1_MASK;
+ break;
+ case 2:
+ mask = GDK_BUTTON2_MASK;
+ break;
+ case 3:
+ mask = GDK_BUTTON3_MASK;
+ break;
+ default:
+ mask = 0;
+ break;
+ }
+
+ if (mods & mask)
+ gtk_dial_update_mouse (dial, x,y);
+ }
+
+ return FALSE;
+}
+
+static gint
+gtk_dial_timer (GtkDial *dial)
+{
+ g_return_val_if_fail (dial != NULL, FALSE);
+ g_return_val_if_fail (GTK_IS_DIAL (dial), FALSE);
+
+ if (dial->policy == GTK_UPDATE_DELAYED)
+ gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
+
+ return FALSE;
+}
+
+static void
+gtk_dial_update_mouse (GtkDial *dial, gint x, gint y)
+{
+ gint xc, yc;
+ gfloat old_value;
+
+ g_return_if_fail (dial != NULL);
+ g_return_if_fail (GTK_IS_DIAL (dial));
+
+ xc = GTK_WIDGET(dial)->allocation.width / 2;
+ yc = GTK_WIDGET(dial)->allocation.height / 2;
+
+ old_value = dial->adjustment->value;
+ dial->angle = atan2(yc-y, x-xc);
+
+ if (dial->angle < -M_PI/2.)
+ dial->angle += 2*M_PI;
+
+ if (dial->angle < -M_PI/6)
+ dial->angle = -M_PI/6;
+
+ if (dial->angle > 7.*M_PI/6.)
+ dial->angle = 7.*M_PI/6.;
+
+ dial->adjustment->value = dial->adjustment->lower + (7.*M_PI/6 - dial->angle) *
+ (dial->adjustment->upper - dial->adjustment->lower) / (4.*M_PI/3.);
+
+ if (dial->adjustment->value != old_value)
+ {
+ if (dial->policy == GTK_UPDATE_CONTINUOUS)
+ {
+ gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
+ }
+ else
+ {
+ gtk_widget_draw (GTK_WIDGET(dial), NULL);
+
+ if (dial->policy == GTK_UPDATE_DELAYED)
+ {
+ if (dial->timer)
+ gtk_timeout_remove (dial->timer);
+
+ dial->timer = gtk_timeout_add (SCROLL_DELAY_LENGTH,
+ (GtkFunction) gtk_dial_timer,
+ (gpointer) dial);
+ }
+ }
+ }
+}
+</verb></tscreen>
+
+<p>
+Cambiamenti esterni all'Adjustment sono comunicati al nostro widget
+dai segnali ``changed'' e ``value_changed''. Il gestore per
+queste funzioni chiama <tt/gtk_dial_update()/ per validare gli
+argomenti, calcolare il nuovo angolo del puntatore e ridisegnare il
+widget (chiamando <tt/gtk_widget_draw()/).
+
+<tscreen><verb>
+static void
+gtk_dial_update (GtkDial *dial)
+{
+ gfloat new_value;
+
+ g_return_if_fail (dial != NULL);
+ g_return_if_fail (GTK_IS_DIAL (dial));
+
+ new_value = dial->adjustment->value;
+
+ if (new_value < dial->adjustment->lower)
+ new_value = dial->adjustment->lower;
+
+ if (new_value > dial->adjustment->upper)
+ new_value = dial->adjustment->upper;
+
+ if (new_value != dial->adjustment->value)
+ {
+ dial->adjustment->value = new_value;
+ gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
+ }
+
+ dial->angle = 7.*M_PI/6. - (new_value - dial->adjustment->lower) * 4.*M_PI/3. /
+ (dial->adjustment->upper - dial->adjustment->lower);
+
+ gtk_widget_draw (GTK_WIDGET(dial), NULL);
+}
+
+static void
+gtk_dial_adjustment_changed (GtkAdjustment *adjustment,
+ gpointer data)
+{
+ GtkDial *dial;
+
+ g_return_if_fail (adjustment != NULL);
+ g_return_if_fail (data != NULL);
+
+ dial = GTK_DIAL (data);
+
+ if ((dial->old_value != adjustment->value) ||
+ (dial->old_lower != adjustment->lower) ||
+ (dial->old_upper != adjustment->upper))
+ {
+ gtk_dial_update (dial);
+
+ dial->old_value = adjustment->value;
+ dial->old_lower = adjustment->lower;
+ dial->old_upper = adjustment->upper;
+ }
+}
+
+static void
+gtk_dial_adjustment_value_changed (GtkAdjustment *adjustment,
+ gpointer data)
+{
+ GtkDial *dial;
+
+ g_return_if_fail (adjustment != NULL);
+ g_return_if_fail (data != NULL);
+
+ dial = GTK_DIAL (data);
+
+ if (dial->old_value != adjustment->value)
+ {
+ gtk_dial_update (dial);
+
+ dial->old_value = adjustment->value;
+ }
+}
+</verb></tscreen>
+
+<sect2> Possibili Miglioramenti
+
+<p>
+
+Il widget Dial, da come l'abbiamo costruito, &egrave; lungo circa 670 linee
+di codice C. Anche se questo potrebbe sembrare un po' troppo, abbiamo
+realmente fatto un bel po' con quel tanto di codice, specialmente
+considerando che molta della lunghezza &egrave; costituita da file header e
+commmenti. Comunque ci sono alcuni miglioramenti che potrebbero essere
+fatti a questo widget:
+
+<itemize>
+<item> Se tu provate questo widget, troverete che ci sono alcuni lampeggiamenti
+quando il puntatore viene trascinato in giro. Questo
+perch&egrave; l'intero widget &egrave; cancellato ogni volta che il
+puntatore viene mosso, prima di essere ridisegnato. Spesso, il modo migliore
+per gestire questo tipo di problema &egrave; il disegnare il tutto su una
+pixmap non visibile, poi copiare il risultato finale sullo schermo
+in una passata sola (il widget ProgressBar viene disegnato in questo
+modo).
+
+<item> L'utente potrebbe essere abilitato ad usare le frecce su e giu per
+incrementare e diminuire il valore.
+
+<item> Potrebbe essere carino se il widget avesse i bottoni per
+incrementare e decrementare il valore di step. Anche se potrebbe essere
+possibile usare dei widget Bottone incorporati per questo, possiamo anche
+far s&igrave; che il bottone sia auto-ripentente quando premuto, come le frecce
+in una barra di scorrimento. Molto del codice per implementare questo tipo di
+comportamento pu&ograve; essere trovato nel widget GtkRange.
+
+<item> il widget Dial potrebbe essere fatto/creato dentro un widget
+contenitore con un singolo widget figlio posizionato all'inizio tra i
+2 bottoni menzionati prima. L'utente potrebbe poi aggiungere o una etichetta
+o un widget ``entry'' per mostrare il valore corrente del dial.
+
+</itemize>
+
+<sect1> Impararne di pi&ugrave;
+
+<p>
+Fin qui abbiamo esposto solo una piccola parte di tutto quello che serve
+per creare un widget. Se volete davvero scrivere un vostro widget, la
+miglior risorsa di esempi &egrave; lo stesso codice sorgente GTK. Chiedete a voi
+stessi alcune cose su come deve essere il widget che volete scrivere: &egrave;
+un widget contenitore? dovr&agrave; avere una propria finestra? &egrave; una modifica di
+un widget precedente? Trovate poi un widget simile e iniziate a fargli
+delle modifiche.
+Buone Fortuna.
+
+
+<sect>Scribble, Un semplice esempio di Programma di Disegno
+
+<sect1> Panoramica
+
+<p>
+In questa sezione, creeremo un semplice programma di disegno. Durante
+questo processo, esamineremo come gestire gli eventi generati dal mouse,
+come disegnare all'interno di una finestra e come disegnare in modo migliore
+usando una pixmap di supporto. Dopo averlo creato, lo amplieremo aggiungendo
+il supporto per i dispositivi XInput, per esempio le tavolette grafiche.
+Il GTK fornisce delle routine di supporto grazie alle quali risulta piuttosto
+semplice ottenere informazioni estese, come la pressione o l'inclinazione.
+
+<sect1> Gestione degli Eventi
+
+<p>
+I segnali di GTK che abbiamo discusso finora si riferivano ad azioni di
+alto livello, ad esempio la selezione di un elemento di un men&ugrave;. Per&ograve;, a volte
+&egrave; utile sapere qualcosa su cose che si svolgono a livello pi&ugrave; basso livello,
+come possono essere il movimento del mouse o la pressione di un tasto.
+Ci sono segnali di GTK anche per questi <em>eventi</em> di basso livello.
+I gestori di questo tipo di segnali hanno un parametro caratteristico in pi&ugrave;,
+che &egrave; il puntatore ad una struttura che contiene informazioni riguardo
+all'evento. Per esempio, ai gestori di eventi che riguardano dei movimenti,
+si passa un puntatore ad una struttura GdkEventMotion, che &egrave; fatta (in parte)
+cos&igrave;:
+
+<tscreen><verb>
+struct _GdkEventMotion
+{
+ GdkEventType type;
+ GdkWindow *window;
+ guint32 time;
+ gdouble x;
+ gdouble y;
+ ...
+ guint state;
+ ...
+};
+</verb></tscreen>
+
+<tt/type/ avr&agrave; il valore del tipo di evento, in questo caso
+<tt/GDK_MOTION_NOTIFY/, <tt/window/ rappresenta la finestra in cui l'evento
+si &egrave; verificato. <tt/x/ e <tt/y/ forniscono le coordinate dell'evento e
+<tt/state/ specifica lo stato dei modificatori nel momento in cui l'evento
+si &egrave; verificato (cio&egrave;, specifica quali tasti modificatori e tasti del mouse
+erano premuti in quel momento). E' un OR bit per bit dei seguenti valori:
+
+<tscreen><verb>
+GDK_SHIFT_MASK
+GDK_LOCK_MASK
+GDK_CONTROL_MASK
+GDK_MOD1_MASK
+GDK_MOD2_MASK
+GDK_MOD3_MASK
+GDK_MOD4_MASK
+GDK_MOD5_MASK
+GDK_BUTTON1_MASK
+GDK_BUTTON2_MASK
+GDK_BUTTON3_MASK
+GDK_BUTTON4_MASK
+GDK_BUTTON5_MASK
+</verb></tscreen>
+
+<p>
+Come succede per gli altri segnali, per determinare cosa deve accadere in
+corrispondenza di un evento, si chiama <tt>gtk_signal_connect()</tt>. Ma
+&egrave; anche necessario far s&igrave; che GTK sappia di quali eventi vogliamo essere
+informati. A questo fine, chiamiamo la funzione:
+
+<tscreen><verb>
+void gtk_widget_set_events (GtkWidget *widget, gint events);
+</verb></tscreen>
+
+Il secondo campo specifica gli eventi che ci interessano. Si tratta dell'OR
+bit per bit delle costanti che identificano i diversi tipi di eventi. La lista
+dei tipi di eventi &egrave; la seguente:
+
+<tscreen><verb>
+GDK_EXPOSURE_MASK
+GDK_POINTER_MOTION_MASK
+GDK_POINTER_MOTION_HINT_MASK
+GDK_BUTTON_MOTION_MASK
+GDK_BUTTON1_MOTION_MASK
+GDK_BUTTON2_MOTION_MASK
+GDK_BUTTON3_MOTION_MASK
+GDK_BUTTON_PRESS_MASK
+GDK_BUTTON_RELEASE_MASK
+GDK_KEY_PRESS_MASK
+GDK_KEY_RELEASE_MASK
+GDK_ENTER_NOTIFY_MASK
+GDK_LEAVE_NOTIFY_MASK
+GDK_FOCUS_CHANGE_MASK
+GDK_STRUCTURE_MASK
+GDK_PROPERTY_CHANGE_MASK
+GDK_PROXIMITY_IN_MASK
+GDK_PROXIMITY_OUT_MASK
+</verb></tscreen>
+
+Per chiamare <tt/gtk_widget_set_events()/, si devono fare alcune osservazioni
+sottili. In primo luogo, la si deve chiamare prima che sia stata creata la
+finestra X per il widget GTK. In pratica, ci&ograve; significa che la si deve
+chiamare subito dopo aver creato il widget. In secondo luogo, il widget
+deve avere una finestra X associata. Molti widget, per ragioni di
+efficienza, non hanno una propria finetra, e vengono mostrati nella
+finestra madre. Questi widget sono:
+
+<tscreen><verb>
+GtkAlignment
+GtkArrow
+GtkBin
+GtkBox
+GtkImage
+GtkItem
+GtkLabel
+GtkPaned
+GtkPixmap
+GtkScrolledWindow
+GtkSeparator
+GtkTable
+GtkViewport
+GtkAspectFrame
+GtkFrame
+GtkVPaned
+GtkHPaned
+GtkVBox
+GtkHBox
+GtkVSeparator
+GtkHSeparator
+</verb></tscreen>
+
+Per catturare degli eventi per questo tipo di widget, si deve fare uso
+del widget EventBox. Si veda a questo proposito la sezione su
+<ref id="sec_The_EventBox_Widget" name="The EventBox Widget">.
+
+<p>
+Per il nostro programma di disegno, vogliamo sapere quando il pulsante del
+mouse &egrave; premuto e quando viene mosso, quindi specificheremo
+<tt/GDK_POINTER_MOTION_MASK/ e <tt/GDK_BUTTON_PRESS_MASK/. Vogliamo anche
+essere informati su quando &egrave; necessario ridisegnare la nostra finestra,
+quindi specifichiamo <tt/GDK_EXPOSURE_MASK/. Anche se vogliamo essere
+avvertiti con un evento ``Configure'' se la dimensione della nostra finestra
+cambia, non &egrave; necessario specificare il flag <tt/GDK_STRUCTURE_MASK/, dal
+momento che questo viene specificato automaticamente per tutte le finestre.
+
+<p>
+Risulta, conunque, che specificando semplicemente <tt/GDK_POINTER_MOTION_MASK/
+si crea un problema. Ci&ograve; infatti fa s&igrave; che il server aggiunga nella coda un
+un nuovo evento di movimento ogni volta che l'utente muovoe il mouse. Immaginate
+che ci vogliano 0.1 secondi per gestire uno di questi eventi, e che il server
+X metta in coda un nuovo evento ogni 0.05 secondi. Rimarremo ben presto indietro
+rispetto al disegno dell'utente. Se l'utente disegna per 5 secondi, ci metteremmo
+altri 5 secondi prima di finire dopo che l'utente ha rilasciato il pulsante del
+mouse! Vorremmo quindi che venga notificato un solo evento di movimento per
+ogni evento che processiamo. Il modo per farlo &egrave; di specificare
+<tt/GDK_POINTER_MOTION_HINT_MASK/.
+
+<p>
+Quando specifichiamo <tt/GDK_POINTER_MOTION_HINT_MASK/, il server ci notifica
+un evento di movimento la prima volta che il puntatore si muove dopo essere
+entrato nella nostra finestra, oppure dopo ogni rilascio di un pulsante del
+mouse. Gli altri eventi di movimento verranno soppressi finch&eacute; non richiediamo
+esplicitamente la posizione del puntatore con la funzione:
+
+<tscreen><verb>
+GdkWindow* gdk_window_get_pointer (GdkWindow *window,
+ gint *x,
+ gint *y,
+ GdkModifierType *mask);
+</verb></tscreen>
+
+(c'&egrave; anche un'altra funzione, <tt>gtk_widget_get_pointer()</tt>, che ha
+un'interfaccia pi&ugrave; semplice, ma che non risulta molto utile dal momento
+che restituisce solo la posizione del puntatore, senza dettagli sullo
+sato dei pulsanti.)
+
+<p>
+Quindi, il codice per assegnare gli eventi per la nostra finestra, avr&agrave; l'aspetto:
+
+<tscreen><verb>
+ gtk_signal_connect (GTK_OBJECT (drawing_area), "expose_event",
+ (GtkSignalFunc) expose_event, NULL);
+ gtk_signal_connect (GTK_OBJECT(drawing_area),"configure_event",
+ (GtkSignalFunc) configure_event, NULL);
+ gtk_signal_connect (GTK_OBJECT (drawing_area), "motion_notify_event",
+ (GtkSignalFunc) motion_notify_event, NULL);
+ gtk_signal_connect (GTK_OBJECT (drawing_area), "button_press_event",
+ (GtkSignalFunc) button_press_event, NULL);
+
+ gtk_widget_set_events (drawing_area, GDK_EXPOSURE_MASK
+ | GDK_LEAVE_NOTIFY_MASK
+ | GDK_BUTTON_PRESS_MASK
+ | GDK_POINTER_MOTION_MASK
+ | GDK_POINTER_MOTION_HINT_MASK);
+</verb></tscreen>
+
+Teniamo per dopo i gestori di ``expose_event'' e ``configure_event''. Quelli di
+``motion_notify_event'' e ``button_press_event'' sono piuttosto semplici:
+
+<tscreen><verb>
+static gint
+button_press_event (GtkWidget *widget, GdkEventButton *event)
+{
+ if (event->button == 1 &amp;&amp; pixmap != NULL)
+ draw_brush (widget, event->x, event->y);
+
+ return TRUE;
+}
+
+static gint
+motion_notify_event (GtkWidget *widget, GdkEventMotion *event)
+{
+ int x, y;
+ GdkModifierType state;
+
+ if (event->is_hint)
+ gdk_window_get_pointer (event->window, &amp;x, &amp;y, &amp;state);
+ else
+ {
+ x = event->x;
+ y = event->y;
+ state = event->state;
+ }
+
+ if (state &amp; GDK_BUTTON1_MASK &amp;&amp; pixmap != NULL)
+ draw_brush (widget, x, y);
+
+ return TRUE;
+}
+</verb></tscreen>
+
+
+<sect1> Il widget Area di Disegno (DrawingArea) e il procedimento per Disegnare
+
+<p>
+Vediamo ora il procedimento per disegnare sullo schermo. Il
+widget da usare &egrave; l'Area di Disegno (DrawingArea). Essenzialmente si
+tratta di una finestra X e nient'altro. E' una tela bianca su cui possimo
+disegnare tutto quello che vogliamo. Per crearne una usiamo la chiamata:
+
+<tscreen><verb>
+GtkWidget* gtk_drawing_area_new (void);
+</verb></tscreen>
+
+Per specificare una dimensione predefinita, si puo fare:
+
+<tscreen><verb>
+void gtk_drawing_area_size (GtkDrawingArea *darea,
+ gint width,
+ gint height);
+</verb></tscreen>
+
+Come &egrave; vero per tutti i widget, si pu&ograve; modificare questa dimensione
+predefinita, tramite la chamata a <tt>gtk_widget_set_usize()</tt>, e
+questa a sua volta pu&ograve; essere modificata dall'utente ridimensionando
+manualmente la finestra che contiene l'area di disegno.
+
+<p>
+Si deve notare che nel momento in cui creiamo un widget DrawingArea, siamo
+<em>completamente</em> responsabili di disegnarne il contenuto. Se ad
+esempio la nostra finestra viene prima nascosta e poi dinuovo portata in
+primo piano, otteniamo un evento di ``esposizione'' e doppiamo ridisegnare
+ci&ograve; che era stato precedente nascosto.
+
+<p>
+Dover ricordare tutto quello che era disegnato sulla finestra in modo da
+poterlo ridisegnare successivamente, pu&ograve; essere, come minimo, noioso.
+In pi&ugrave;, pu&ograve; essere spiacevole dal punto di vista visivo, se delle porzioni
+dello schermo vengono prima cancellate e poi ridisegnate passo per passo.
+La soluzione per questo problema &egrave; di usare una <em>pixmap di supporto</em>.
+Invece di disegnare direttamente sullo schermo, disegnamo su un'iimagine
+conservata nella memoria del server ma che non viene mostrata; quindi, quando
+l'immagine cambia o ne vengono mostrate nuove porzioni, copiamo sullo schermo
+le parti corrispondenti.
+
+<p>
+Per creare una ppixmap fuori dallo schermo, usiamo la funzione:
+
+<tscreen><verb>
+GdkPixmap* gdk_pixmap_new (GdkWindow *window,
+ gint width,
+ gint height,
+ gint depth);
+</verb></tscreen>
+
+Il parametro <tt>window</tt>specifica una finestra GDK dalla quale questa
+pixmap prende alcune delle sue propriet&agrave;. <tt>width</tt> e <tt>height</tt>
+specificano le dimensioni della pixmap. <tt>depth</tt> specifica la
+<em>profondit&agrave; di colore</em>, cio&egrave; il numero di bit per ogni pixel, per
+la nuova pixmap. Se alla profondit&agrave; &egrave; assegnato il valore <tt>-1</tt>, questa
+verr&agrave; posta identica a quella di <tt>window</tt>.
+
+<p>
+Creiamo la pixmap all'interno del gestore di ``configure_event''. Questo evento
+&egrave; generato ogni volta che la finestra cambia di dimensione, compreso il
+momento in cui viene creata per la prima volta.
+
+<tscreen><verb>
+/* Pixmap di supporto per l'area di disegno */
+static GdkPixmap *pixmap = NULL;
+
+/* Creare una pixmap della dimensione appropriata */
+static gint
+configure_event (GtkWidget *widget, GdkEventConfigure *event)
+{
+ if (pixmap)
+ {
+ gdk_pixmap_destroy(pixmap);
+ }
+ pixmap = gdk_pixmap_new(widget->window,
+ widget->allocation.width,
+ widget->allocation.height,
+ -1);
+ gdk_draw_rectangle (pixmap,
+ widget->style->white_gc,
+ TRUE,
+ 0, 0,
+ widget->allocation.width,
+ widget->allocation.height);
+
+ return TRUE;
+}
+</verb></tscreen>
+
+La chiamata a <tt>gdk_draw_rectangle()</tt> inizialmente rende bianca l'intera
+pixmap. Fra un momento ne riparleremo.
+
+<p>
+Il gestore dell'evento ``esposizione'', copia quindi la porzione appropriata
+della pixmap sullo schermo (determiniamo qual &egrave; l'area da ridisegnare usando
+il campo event->area dell'evento di esposizione):
+
+<tscreen><verb>
+/* Ridisegna sullo schermo a partire dalla pixmap di supporto */
+static gint
+expose_event (GtkWidget *widget, GdkEventExpose *event)
+{
+ gdk_draw_pixmap(widget->window,
+ widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
+ pixmap,
+ event->area.x, event->area.y,
+ event->area.x, event->area.y,
+ event->area.width, event->area.height);
+
+ return FALSE;
+}
+</verb></tscreen>
+
+Abbiamo quindi visto come tenete aggiornato lo schermo con la nostra
+pixmap, ma come facciamo per disegnare delle cose interessanti sulla
+pixmap? Ci sono un bel po' di funzioni nella libreria GDK di GTK che
+servono per disegnare su superfici <em>disegnabili</em>. Una superficie
+disegnabile &egrave; semplicemente qualcosa su cui si pu&ograve; disegnare un'immagine.
+Pu&ograve; essere una finestra, una pixmap o una bitmap (un'immagine in bianco e
+nero). Abbiamo gi&agrave; visto sopra due di chiamate,
+<tt>gdk_draw_rectangle()</tt> and <tt>gdk_draw_pixmap()</tt>. La lista
+completa &egrave; la seguente:
+
+<tscreen><verb>
+gdk_draw_line ()
+gdk_draw_rectangle ()
+gdk_draw_arc ()
+gdk_draw_polygon ()
+gdk_draw_string ()
+gdk_draw_text ()
+gdk_draw_pixmap ()
+gdk_draw_bitmap ()
+gdk_draw_image ()
+gdk_draw_points ()
+gdk_draw_segments ()
+</verb></tscreen>
+
+Per ulteriori dettagli su queste funzioni, vedete la documentazione di
+riferimento nei file header <tt>&lt;gdk/gdk.h&gt;</tt>.
+Tutte queste funzioni hanno i medesimi primi due argomenti. Il primo
+&egrave; la superficie disegnabili su cui disegnare, il secondo &egrave; un
+<em>contesto grafico</em> (GC).
+
+<p>
+Un contesto grafico incapsula delle informazioni riguardo a cose come
+il colore di sfondo e di primo piano e lo spessore della linea.
+GDK ha un ampio insieme di funzioni per crare e modificare contesti grafici,
+ma per tenere le cose semplici useremo solo dei contesti grafici predefiniti.
+Ogni widget ha uno stile associato (che pu&ograve; essere modificato agendo su un
+file gtkrc). Questo, fra le altre cose, contiene un certo numero di contesti
+grafici. Alcuni esempi di come accedere a questi contesti grafici sono
+i seguenti:
+
+<tscreen><verb>
+widget->style->white_gc
+widget->style->black_gc
+widget->style->fg_gc[GTK_STATE_NORMAL]
+widget->style->bg_gc[GTK_WIDGET_STATE(widget)]
+</verb></tscreen>
+
+I campi <tt>fg_gc</tt>, <tt>bg_gc</tt>, <tt>dark_gc</tt>, e
+<tt>light_gc</tt> sono indicizzati tramite un parametri di tipo
+<tt>GtkStateType</tt>, che pu&ograve; assumere i valori:
+
+<tscreen><verb>
+GTK_STATE_NORMAL,
+GTK_STATE_ACTIVE,
+GTK_STATE_PRELIGHT,
+GTK_STATE_SELECTED,
+GTK_STATE_INSENSITIVE
+</verb></tscreen>
+
+Per esempio, per <tt/GTK_STATE_SELECTED/ il colore di sfondo predefinito
+&egrave; blu scuro e quello di primo piano bianco.
+
+<p>
+La nostra funzione <tt>draw_brush()</tt>, che efettivamente disegna sullo
+schermo, diventa quindi:
+
+<tscreen><verb>
+/* Disegna un rettangolo sullo schermo */
+static void
+draw_brush (GtkWidget *widget, gdouble x, gdouble y)
+{
+ GdkRectangle update_rect;
+
+ update_rect.x = x - 5;
+ update_rect.y = y - 5;
+ update_rect.width = 10;
+ update_rect.height = 10;
+ gdk_draw_rectangle (pixmap,
+ widget->style->black_gc,
+ TRUE,
+ update_rect.x, update_rect.y,
+ update_rect.width, update_rect.height);
+ gtk_widget_draw (widget, &amp;update_rect);
+}
+</verb></tscreen>
+
+Dopo aver disegnato il rettangolo sulla pixmap, chiamiamo la funzione:
+
+<tscreen><verb>
+void gtk_widget_draw (GtkWidget *widget,
+ GdkRectangle *area);
+</verb></tscreen>
+
+che notifica a X che l'area data dal parametro <tt>area</tt> deve essere
+aggiornata. X poi generer&agrave; un evento di esposizione (che pu&ograve; essere combinato
+con le aree passate da diverse chiamate a <tt>gtk_widget_draw()</tt>) che
+far&agrave; s&igrave; che il nostro gestore dell'evento di esposizione, copi le porzioni
+rilevanti sullo schermo.
+
+<p>
+Abbiamo a questo punto creato tutto il programma di disegno, tranne che
+per qualche dettaglio irrilevante come la creazione della finestra principale.
+Il codice sorgente completo &egrave; reperibile dove avete ottenuto questo tutorial.
+
+<sect1> Aggiungere il supporto per XInput
+
+<p>
+Al giorno d'oggi &egrave; possibile acquistare dei dispositivi abbastanza a buon
+mercato, come tavolette grafice, che permettono di disegnare con una
+espressivit&agrave; artistica molto semplificata rispetto ad un mouse.
+Il modo pi&ugrave; semplice per usare questi dispositivi &egrave; di sostituirli
+semplicemente al mouse, ma in questo modo si perdono molti dei loro
+vantaggi, come:
+
+<itemize>
+<item> Sensibilit&agrave; alla pressione
+<item> Sensibilit&agrave; all'inclinazione
+<item> Posizionamento infra-pixel
+<item> Ingressi multipli (per esempio, uno stilo che contiene sia una ``matita''
+sia una ``gomma'')
+</itemize>
+
+Per ulteriori informazioni sulle estensioni XInput, vedere l'<url
+url="http://www.msc.cornell.edu/~otaylor/xinput/XInput-HOWTO.html"
+name="XInput-HOWTO">.
+
+<p>
+Se esaminiamo, per esempio, la definizione completa della struttura
+GdkEventMotion, possiamo vedere che contiene dei campi per il supporto
+delle informazioni estese dai dispositivi.
+
+<tscreen><verb>
+struct _GdkEventMotion
+{
+ GdkEventType type;
+ GdkWindow *window;
+ guint32 time;
+ gdouble x;
+ gdouble y;
+ gdouble pressure;
+ gdouble xtilt;
+ gdouble ytilt;
+ guint state;
+ gint16 is_hint;
+ GdkInputSource source;
+ guint32 deviceid;
+};
+</verb></tscreen>
+
+<tt/pressure/ fornisce la pressione sotto forma di un numero decimale
+compreso fra 0 e 1. <tt/xtilt/ e <tt/ytilt/ possono assumere valori
+compresi fra -1 e 1, corrispondenti al grado di inclinazione in ciascuna
+direzione. <tt/source/ e <tt/deviceid/ specificano il dispositivo per il
+quale si &egrave; verificato l'evento in due modi distinti. <tt/source/ da alcune
+semplici informazioni sul tipo di dispositivo, e pu&ograve; assumere i valori:
+
+<tscreen><verb>
+GDK_SOURCE_MOUSE
+GDK_SOURCE_PEN
+GDK_SOURCE_ERASER
+GDK_SOURCE_CURSOR
+</verb></tscreen>
+
+<tt/deviceid/ specifica invece un identificativo numerico univoco per il
+dispositivo. Questo pu&ograve; essere a sua volta utilizzato per avere ulteriori
+informazioni sul dispositivo tramite la chiamata a <tt/gdk_input_list_devices()/
+(vedi sotto). Il valore speciale <tt/GDK_CORE_POINTER/ viene usato per identificare
+il dispositivo di puntamento principale (di solito il mouse).
+
+<sect2> Abilitare le informazioni estese
+
+<p>
+Per far s&igrave; che GTK sappia che ci interessano le informazioni estese dai
+dispositivi, basta aggiungere un'unica linea al nostro programma:
+
+<tscreen><verb>
+gtk_widget_set_extension_events (drawing_area, GDK_EXTENSION_EVENTS_CURSOR);
+</verb></tscreen>
+
+Dando il valore <tt/GDK_EXTENSION_EVENTS_CURSOR/, diciamo che ci interessano
+gli eventi relativi alle estensioni, ma solo se non dobbiamo disegnare da noi
+il nostro cursore. Si veda pi&ugrave; sotto alla sezione <ref
+id="sec_Further_Sophistications" name="Ulteriori Sofisticazioni"> per ulteriori
+informazioni sul modo si disegnare i cursori. Potremmo anche dare i valori
+<tt/GDK_EXTENSION_EVENTS_ALL/ se vogliamo disegnare il nostro cursore o
+<tt/GDK_EXTENSION_EVENTS_NONE/ se vogliamo tornare alle condizioni predefinite.
+
+<p>
+Comunque, non finisce tutto qui. Non ci sono estensioni abilitate per difetto.
+Abbiamo bisogno di un meccanismo per permettere agli utenti l'abilitazione e
+la configurazione delle estensioni dei loro dispositivi, GTK fornisce il
+widget InputDialog per automatizzare questo processo. La seguente procedura
+mostra come gestire un widget InputDialog. Crea la finestra di dialogo nel
+caso non sia presente, mentre la porta in primo piano in caso contrario.
+
+<tscreen><verb>
+void
+input_dialog_destroy (GtkWidget *w, gpointer data)
+{
+ *((GtkWidget **)data) = NULL;
+}
+
+void
+create_input_dialog ()
+{
+ static GtkWidget *inputd = NULL;
+
+ if (!inputd)
+ {
+ inputd = gtk_input_dialog_new();
+
+ gtk_signal_connect (GTK_OBJECT(inputd), "destroy",
+ (GtkSignalFunc)input_dialog_destroy, &amp;inputd);
+ gtk_signal_connect_object (GTK_OBJECT(GTK_INPUT_DIALOG(inputd)->close_button),
+ "clicked",
+ (GtkSignalFunc)gtk_widget_hide,
+ GTK_OBJECT(inputd));
+ gtk_widget_hide ( GTK_INPUT_DIALOG(inputd)->save_button);
+
+ gtk_widget_show (inputd);
+ }
+ else
+ {
+ if (!GTK_WIDGET_MAPPED(inputd))
+ gtk_widget_show(inputd);
+ else
+ gdk_window_raise(inputd->window);
+ }
+}
+</verb></tscreen>
+
+(Notate come gestiamo questo dialogo. Con la connessione del segnale
+``destroy'' ci assicuriamo di non tenerci in giro il puntatore al dialogo
+dopo che lo abbiamo distrutto, cosa che potrebbe portare ad un errore di
+segmentazione.)
+
+<p>
+L'InputDialog ha due pulsanti, ``Close'' e ``Save'', i quali non hanno alcuna
+azione predefinita assegnata ad essi. Nella funzione precedente, abbiamo
+fatto in modo che ``Close'' nasconda la finestra di dialogo, e abbiamo nascosto
+il pulsante ``Save'' dal momento che in questo programma non implementiamo il
+salvataggio delle opzioni di XInput.
+
+<sect2> Usare le informazioni estese
+
+<p>
+Una volta abilitato il dipositivo, possiamo usare le informazioni estese
+che si trovano nei corrispondenti campi delle strutture che descrivono gli
+eventi. A dire il vero, l'utilizzo di questi campi &egrave; sempre sicuro, perch&eacute;
+sono tutti posti per difetto a valori ragionevoli ancje quando la gestione
+degli eventi estesi non &egrave; abilitata.
+
+<p>
+Un cambiamento che dobbiamo fare &egrave; di chiamare <tt/gdk_input_window_get_pointer()/
+invece di <tt/gdk_window_get_pointer/. Ci&ograve; si rende necessario perch&eacute;
+<tt/gdk_window_get_pointer/ non restituisce le informazioni esetese.
+
+<tscreen><verb>
+void gdk_input_window_get_pointer (GdkWindow *window,
+ guint32 deviceid,
+ gdouble *x,
+ gdouble *y,
+ gdouble *pressure,
+ gdouble *xtilt,
+ gdouble *ytilt,
+ GdkModifierType *mask);
+</verb></tscreen>
+
+Quando chiamiamo questa funzione, dobbiamo specificare l'identificativo
+del dispositivo e la finestra. Normalmente questo identificativo lo si
+ottiene dal campo <tt/deviceid/ della struttura dell'evento.
+Questa funzione restituir&agrave; valori ragionevoli nel caso che la gestione
+degli eventi estesi non sia attivata (in questo caso, <tt/event->deviceid/
+avr&agrave; il valore <tt/GDK_CORE_POINTER/).
+
+Quindi, la struttura di base dei gestori degli eventi relativi alla
+pressione di bottoni e ai movomenti non cambia molto - abbiamo solo
+bisogno di aggiungere il codice necessario per tenere conto delle
+informazioni estese.
+
+<tscreen><verb>
+static gint
+button_press_event (GtkWidget *widget, GdkEventButton *event)
+{
+ print_button_press (event->deviceid);
+
+ if (event->button == 1 &amp;&amp; pixmap != NULL)
+ draw_brush (widget, event->source, event->x, event->y, event->pressure);
+
+ return TRUE;
+}
+
+static gint
+motion_notify_event (GtkWidget *widget, GdkEventMotion *event)
+{
+ gdouble x, y;
+ gdouble pressure;
+ GdkModifierType state;
+
+ if (event->is_hint)
+ gdk_input_window_get_pointer (event->window, event->deviceid,
+ &amp;x, &amp;y, &amp;pressure, NULL, NULL, &amp;state);
+ else
+ {
+ x = event->x;
+ y = event->y;
+ pressure = event->pressure;
+ state = event->state;
+ }
+
+ if (state &amp; GDK_BUTTON1_MASK &amp;&amp; pixmap != NULL)
+ draw_brush (widget, event->source, x, y, pressure);
+
+ return TRUE;
+}
+</verb></tscreen>
+
+Avremo anche bisogno di fare qualcosa con queste nuove informazioni. La
+nostra nuova funzione <tt/draw_brush/ disegna con un colore diverso per
+ogni <tt/event->source/ e cambia la dimensione della linea in funzione
+della pressione.
+
+<tscreen><verb>
+/* Disegna un rettangolo sullo schermo, con la dimensione dipendente
+ dalla pressione e il colore dipendente dal tipo di dispositivo */
+static void
+draw_brush (GtkWidget *widget, GdkInputSource source,
+ gdouble x, gdouble y, gdouble pressure)
+{
+ GdkGC *gc;
+ GdkRectangle update_rect;
+
+ switch (source)
+ {
+ case GDK_SOURCE_MOUSE:
+ gc = widget->style->dark_gc[GTK_WIDGET_STATE (widget)];
+ break;
+ case GDK_SOURCE_PEN:
+ gc = widget->style->black_gc;
+ break;
+ case GDK_SOURCE_ERASER:
+ gc = widget->style->white_gc;
+ break;
+ default:
+ gc = widget->style->light_gc[GTK_WIDGET_STATE (widget)];
+ }
+
+ update_rect.x = x - 10 * pressure;
+ update_rect.y = y - 10 * pressure;
+ update_rect.width = 20 * pressure;
+ update_rect.height = 20 * pressure;
+ gdk_draw_rectangle (pixmap, gc, TRUE,
+ update_rect.x, update_rect.y,
+ update_rect.width, update_rect.height);
+ gtk_widget_draw (widget, &amp;update_rect);
+}
+</verb></tscreen>
+
+<sect2> Trovare ulteriori informazioni su di un dispositivo
+
+<p>
+Come esempio del modo di trovare altre informazioni su di un dispositivo,
+il nostro programma stamper&agrave; il nome di ogni dispositivo che genera un
+evento di pressione di un pulsante. Per avere il nome di un dispositivo,
+chiamiamo la funzione
+
+<tscreen><verb>
+GList *gdk_input_list_devices (void);
+</verb></tscreen>
+
+che restituisce una GList (un tipo di lista collegata che si trova nella
+libreria glib) di strutture di tipo GdkDeviceInfo. La definizione di
+GdkDeviceInfo &egrave; la seguente:
+
+<tscreen><verb>
+struct _GdkDeviceInfo
+{
+ guint32 deviceid;
+ gchar *name;
+ GdkInputSource source;
+ GdkInputMode mode;
+ gint has_cursor;
+ gint num_axes;
+ GdkAxisUse *axes;
+ gint num_keys;
+ GdkDeviceKey *keys;
+};
+</verb></tscreen>
+
+La maggior parte di questi campi rappresentano informazioni di configurazione
+che potete ignorare a meno che non implementiate il salvataggio della
+configurazione di un XInput. Quelle che ci interessano sono <tt/name/, che
+&egrave; semplicemente il nome che X assegna al dispositivo, e <tt/has_cursor/. Anche
+<tt/has_cursor/ non &egrave; informazione di configurazione, e indica, nel caso
+abbia valore ``falso'', che dobbiamo disegnare da soli il nostro cursore. Ma
+dal momento che abbiamo specificato <tt/GDK_EXTENSION_EVENTS_CURSOR/,
+possiamo anche non preoccuparcene.
+
+<p>
+
+La nostra funzione <tt/print_button_press()/ scorre semplicemente la lista
+che &egrave; stata restituita finch&eacute; non trova il valore corretto, e poi stampa
+il nome del dispositivo.
+
+<tscreen><verb>
+static void
+print_button_press (guint32 deviceid)
+{
+ GList *tmp_list;
+
+ /* gdk_input_list_devices restituisce una lista interna, cos&igrave; poi
+ non dobbiamo liberarla */
+ tmp_list = gdk_input_list_devices();
+
+ while (tmp_list)
+ {
+ GdkDeviceInfo *info = (GdkDeviceInfo *)tmp_list->data;
+
+ if (info->deviceid == deviceid)
+ {
+ printf("Button press on device '%s'\n", info->name);
+ return;
+ }
+
+ tmp_list = tmp_list->next;
+ }
+}
+</verb></tscreen>
+Questo completa i cambiamenti necessari per usare gli XInput nel nostro
+programma. Come per la prima versione, i sorgenti completi sono prelevabili
+da dove avete prelevato questo tutorial.
+
+<sect2> Ulteriori sofisticazioni <label id="sec_Further_Sophistications">
+
+<p>
+Anche se ora il nostro programma supporta XInput pittosto bene, gli mancano
+alcune caratteristiche che probabilmente vorremmo mettere in una applicazione
+completa. In primo luogo, probabilmente all'utente non far&agrave; piacere dover
+configurare i propri dispositivi ogni volta che lanciano il programma, per
+cui dovremmo dare la possibilit&agrave; di salvare la configurazione dei dispositivi.
+Ci&ograve; pu&ograve; essere fatto scorrendo la lista restituita da <tt/gdk_input_list_devices()/
+e scrivendo la configurazione su di un file.
+
+<p>
+Per tornare allo stato salvato la prossima volta che il programma viene
+eseguito, GDK mette a disposizione delle funzioni per cambiare la configurazione
+dei dispositivi:
+
+<tscreen><verb>
+gdk_input_set_extension_events()
+gdk_input_set_source()
+gdk_input_set_mode()
+gdk_input_set_axes()
+gdk_input_set_key()
+</verb></tscreen>
+
+(La lista restituita da <tt/gdk_input_list_devices()/ non dovrebbe
+essere modificata direttamente.) Un esempio di come fare pu&ograve; essere
+trovato nel programma di disegno gsumi (disponibile da <htmlurl
+url="http://www.msc.cornell.edu/~otaylor/gsumi/"
+name="http://www.msc.cornell.edu/~otaylor/gsumi/">). Sarebbe bello
+avere alla fine un modo standard di recuperare le informazioni per tutte
+le applicazioni. Questo probabilmente appartiene ad un livello un po'
+pi&ugrave; elevato ripetto a GTK, forse alla libreria GNOME.
+
+<p>
+Un'altra notevole omissione a cui abbiamo accennato precedentemente &egrave; il
+fatto di non disegnare il cursore direttamente. Piattaforme diverse da
+XFree86 non permettono in questo momento di usare contemporaneamente un
+dispositivo sia come puntatore principale sia direttamente da una
+applicazione. Vedere <url url="http://www.msc.cornell.edu/~otaylor/xinput/XInput-HOWTO.html"
+name="XInput-HOWTO"> per ulteriori informazioni. Ci&ograve; significa che le
+applicazioni che vogliono rivolgersi al pubblico pi&ugrave; ampio dovranno prevedere
+di disegnare esse stesse il proprio cursore.
+
+<p>
+Un'applicazione che voglia disegnare il proprio cursore dovr&agrave; fare due cose:
+determinare se il dispositivo corrente necessita che venga disegnato un
+cursore, e determinare se il dispositivo corrente &egrave; in prossimit&agrave;. (Se il
+dispositivo &egrave; una tavoletta grafica, un tocco di finezza &egrave; fare sparire
+il puntatore quando lo stilo viene sollevato dalla tavoletta. Quando c'&egrave;
+contatto fra lo stilo e la tavoletta, si dice che il dispositivo &egrave; ``in
+prossimit&agrave;".) La prima cosa viene fatta scorrendo la lista dei dispositivi,
+come abbiamo fatto per trovare il nome del dispositivo. La seconda cosa
+viene ottenuta selezionando gli eventi ``proximity_out''. Un esempio di
+disegno del proprio cursore si trova nel programma 'testinput' incluso nella
+distribuzione di GTK.
+
+<sect>Consigli per scrivere Applicazioni GTK
+
+<p>
+
+Questa sezione &egrave; semplicemente una raccolta di saggezza, una
+guida di stile e un aiuto per creare buone applicazioni GTK. E' totalmente
+inutile per ora perch&eacute; &egrave; solamente un appunto.
+
+Usa autoconf e automake! Sono tuoi amici :) Ho intenzione di fare una
+piccola introduzione su di loro qui.
+
+<sect>Contributi
+<p>
+
+Questo documento, come molti altri grandi software fuori di qui, &egrave; stato
+creato da volontari. Se sai tutto quello che c'&egrave; da sapere su GTK e non
+lo hai trovato qui allora considera la possibilit&agrave; di contribuire a questo
+documento.
+
+<p>
+Se decidi di contribuire, per favore trasmettimi il tuo testo a
+<tt><htmlurl url="mailto:slow@intergate.bc.ca"
+name="slow@intergate.bc.ca"></tt>. Inoltre, Si consapevole che l'intero
+documento &egrave; ``free'', e ogni tua aggiunta sar&agrave; considerata allo stesso modo.
+Per questo motivo le persone possono usare porzioni dei tuoi esempi nei loro
+programmi, copie di questo documento possono essere distribuite all'infinito,
+ecc...
+
+<p>
+
+Grazie.
+
+
+<sect>Credits
+<p>
+Voglio qui ringraziare le persone che seguono, per il loro contributo
+alla stesura di questo testo.
+
+<itemize>
+<item>Bawer Dagdeviren, <tt><htmlurl url="mailto:chamele0n@geocities.com"
+name="chamele0n@geocities.com"></tt> per il tutorial sui men&ugrave;.
+
+<item>Raph Levien, <tt><htmlurl url="mailto:raph@acm.org"
+ name="raph@acm.org"></tt>
+per il "hello world" alla GTK, l'immpacchettamento del widget, e in generale
+per tutta la sua saggezza.
+Lui ha anche donato una casa per questo tutorial.
+
+<item>Peter Mattis, <tt><htmlurl url="mailto:petm@xcf.berkeley.edu"
+name="petm@xcf.berkeley.edu"></tt> Per il pi&ugrave; semplice programma GTK e l'abilit&agrave;
+di farlo. :)
+
+<item>Werner Koch <tt><htmlurl url="mailto:werner.koch@guug.de"
+name="werner.koch@guug.de"></tt> per la conversione da testo semplice a SGML
+e la gerarchia delle classi di widget.
+
+<item>Mark Crichton <tt><htmlurl url="mailto:crichton@expert.cc.purdue.edu"
+name="crichton@expert.cc.purdue.edu"></tt> per il codice della "MenuFactory"
+e per la parte sull'impacchettamento nelle tabelle del tutorial.
+
+<item>Owen Taylor <tt><htmlurl url="mailto:owt1@cornell.edu"
+name="mailto:owt1@cornell.edu"></tt> per la sezione del widget EventBox
+(e il patch alla distribuzione). Lui &egrave; anche responsabile per il codice
+e il tutorial delle selezioni, come per la sezione sulla scrittura di un
+proprio widget, e l'applicazione d'esempio. Grazie di tutto Owen.
+
+<item>Mark VanderBoom <tt><htmlurl url="mailto:mvboom42@calvin.edu"
+name="mailto:mailto:mvboom42@calvin.edu"></tt> per il suo meraviglioso lavoro
+sul Notebook, Progres Bar, Dialogs e File selection. Grazie molto Mark. Sei
+stato di grande aiuto.
+
+<item>Tim Janik <tt><htmlurl url="mailto:timj@psynet.net"
+name="mailto:timj@psynet.net"></tt> per il suo grande lavoro sul widget List.
+Grazie Tim :)
+
+<item> Michael K. Johnson <tt><htmlurl url="mailto:johnsonm@redhat.com"
+name="johnsonm@redhat.com"> </tt> per le informazioni e il codice dei menu
+a comparsa.
+
+</itemize>
+<p>
+E a tutti voi che avete fatto commenti e avete aiutato a raffinare questo documento.
+<p>
+
+Thanks.
+
+<sect> Copying
+<p>
+This tutorial is Copyright (c) 1997 Ian Main
+
+La traduzione italiana &egrave; sotto Copyright (c) 1997-1998 di Michel Morelli,
+Daniele Canazza e Antonio Schifano.
+
+<p>
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+<p>
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+<p>
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+</article>
+