]> Pileus Git - ~andy/gtk/blob - docs/tutorial/gtk_tut_it.sgml
added graphics, update tutorials appropriately
[~andy/gtk] / docs / tutorial / gtk_tut_it.sgml
1
2 <!doctype linuxdoc system>
3 <article>
4 <title>GTK Tutorial
5 <author>Ian Main, <tt><htmlurl url="mailto:slow@intergate.bc.ca"
6                               name="slow@intergate.bc.ca"></tt>
7
8 <date>December 1, 1997 - Traduzione Aggiornata al 19 Gennaio 1998
9
10 <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>
11 </abstract>
12
13 <sect>Introduzione
14 <p>
15 GTK (GIMP Toolkit) era orginariamente sviluppato come toolkit per il programma
16 GIMP (General Image Manipulation Program). GTK &egrave; costruito sulla base del
17 kit di disegno di GIMP, il GDK (GIMP Drawing Kit) il quale &egrave; costruito a sua
18 volta attorno alle funzioni della Xlib. E' chiamato ``toolkit di GIMP'' perch&eacute;
19 era inizialmente scritto per sviluppare GIMP, ma ora viene utilizzato nello
20 sviluppo di molti progetti software liberi. Gli autori sono
21 <itemize>
22 <item> Peter Mattis   <tt><htmlurl url="mailto:petm@xcf.berkeley.edu"
23                            name="petm@xcf.berkeley.edu"></tt>     
24 <item> Spencer Kimball <tt><htmlurl url="mailto:spencer@xcf.berkeley.edu"
25                            name="spencer@xcf.berkeley.edu"></tt>
26 <item> Josh MacDonald <tt><htmlurl url="mailto:jmacd@xcf.berkeley.edu"
27                            name="jmacd@xcf.berkeley.edu"></tt>
28 </itemize>
29
30 <p>
31 GTK &egrave; essenzialmente una API (application programmers interface)
32 orientata agli oggetti.
33 Anche se scritto completamente in C, &egrave; implementato usando l'idea delle
34 classi e delle funzioni di callback (puntatori a funzioni).
35
36 <p>
37 C'&egrave; anche una terza componente chiamata glib che contiene una serie di
38 implementazioni differenti di alcune chiamate di funzioni standard e anche
39 alcune funzioni aggiuntive, per esempio per la manipolazione delle liste 
40 collegate, eccetera. Le funzioni sostitutive sono usate per migliorare la 
41 portabilit&agrave; di GTK. Alcune delle funzioni implementate qui non sono
42 disponibili o non sono standard,  altre sono uniche come g_strerror().
43 Altre contengono miglioramenti alle stesse della libc come g_malloc che ha 
44 delle utility di debugging migliorate.
45
46 <p>
47 Questo tutorial &egrave; un tentativo di documentare il meglio possibile la libreria gtk
48 e non pretende di essere completo. Questo tutorial suppone una buona conoscenza del
49 linugaggio C e di come creare programmi in C. Saranno facilitati i lettori che hanno una
50 precedente esperienza nella programmazione in X. Se il GTK &egrave; il primo insieme di widget
51 che studiate, siete pregati di dirmi come avete trovato questo tutorial e che tipo di problemi
52 avete avuto.
53 Notate che c'&egrave; anche una versione per il C++ della libreria GTK (chiamata GTK--), quindi
54 se preferite utilizzare questo linguaggio al posto del C potreste cercare questa versione
55 e non la GTK normale.
56 Ci sono poi un ``wrapper'' Objective C e un collegamento a Guile, ma non ne seguo
57 l'evoluzione.
58
59 <p>
60 Mi farebbe molto piacere conoscere qualsiasi problema che abbiate avuto nell'imparare il GTK
61 da questo documento e apprezzerei anche critiche sul come migliorarlo.
62
63 <sect>Iniziamo
64 <p>
65 La prima cosa da fare &egrave; certamente quella di scaricare il GTK e installarlo. Potete prendere
66 l'ultima versione dal sito ftp.gimp.org nella directory /pub/gimp. Un'altra possibile sorgente
67 di informazioni &egrave; il sito http://www.gimp.org/gtk. GTK usa il comando GNU autoconf per
68 autoconfigurarsi. 
69 Una volta estratti i file dall'archivio tar, eseguite configure --help per vedere una lista delle
70 opzioni del comando configure.
71
72 <p>
73 Per iniziare la nostra introduzione a GTK, cominceremo con il pi&ugrave; semplice programma 
74 possibile . Questo programma crea una finestra con dimensioni (in pixel) di 200x200 e 
75 l'unica possibilit&agrave; di uscita &egrave; di ucciderlo ucciso usando la shell o il Window Manager.
76
77 <tscreen><verb>
78 #include <gtk/gtk.h>
79
80 int main (int argc, char *argv[])
81 {
82     GtkWidget *window;
83     
84     gtk_init (&amp;argc, &amp;argv);
85     
86     window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
87     gtk_widget_show (window);
88     
89     gtk_main ();
90     
91     return 0;
92 }
93 </verb></tscreen>
94
95 Tutti i programmi certamente includeranno &lt;gtk/gtk.h&gt; che dichiara le variabili, le funzioni,
96 le strutture, etc. che saranno usate nella tua applicazione GTK.
97
98 <p>
99 La linea seguente: 
100
101 <tscreen><verb>
102 gtk_init (&amp;argc, &amp;argv);
103 </verb></tscreen>
104
105 invoca la funzione gtk_init(gint *argc, gchar ***argv) che sar&agrave; usata in tutte le
106 applicazioni GTK. Questa funzione sistema alcune cose al posto nostro, come la visuale
107 predefinita e la mappa dei colori, e  procede poi chiamando gdk_init(gint *argc, gchar ***argv).
108 Questa funzione inizializza la libreria per l'uso, setta il gestore predefinito dei segnali
109 e guarda negli argomenti, passati via linea di comando alla tua applicazione, alla ricerca
110 di uno di questi argomenti:
111 <itemize>
112 <item> <tt/--display/
113 <item> <tt/--debug-level/
114 <item> <tt/--no-xshm/
115 <item> <tt/--sync/
116 <item> <tt/--show-events/
117 <item> <tt/--no-show-events/
118 </itemize>
119 <p>
120 Rimuove questi argomenti dalla lista degli argomenti passati, lasciando quelli non
121 riconosciuti a disposizione della tua applicazione che potr&agrave; tenerne conto o ignorarli.
122 In questo modo si crea un set di argomenti standard accettato da tutte le applicazione GTK.
123
124 <p>
125 Le seguenti 2 linee di codice creano e mostrano la finestra.
126
127 <tscreen><verb>
128   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
129   gtk_widget_show (window);
130 </verb></tscreen>
131
132 L'argomento GTK_WINDOW_TOPLEVEL specifica che noi vogliamo che la nostra finestra si
133 sottometta alle decorazioni del windows manager e alla posizione che quest'ultimo indicher&agrave;.
134 Invece di creare una finestra avente dimensioni 0x0, la dimensione di una finestra senza
135 figli (altri widget, come i bottoni, etc) &egrave; predefinita a 200x200 cos&igrave; che si possa manipolarla.
136 La funzione gtk_widget_show()  fa s&igrave; che GTK sappia che abbiamo finito di settare gli
137 attributi di questo widget e che quindi quest'ultimo pu&ograve; essere visualizzato.
138
139 <p>
140 L'ultima linea ci fa entrare nel ciclo principale del GTK.
141
142 <tscreen><verb>
143 gtk_main ();
144 </verb></tscreen>
145
146 gtk_main() &egrave; un'altra chiamata che tu vedrete in tutte le applicazioni GTK. Quando il controllo 
147 raggiunge questo punto, l'applicazione si metter&agrave; a dormire aspettando che si verifichino eventi
148 di X (come la pressione di un bottone o di un tasto), timeout o notifiche di Input/Output dei file
149 Nel nostro esempio, comunque, tutti gli eventi sono ignorati.
150
151 <sect1>Hello World in GTK
152 <p>
153 Ok, ora un programma con un widget (un bottone). E' il classico ``Hello World'' alla GTK. 
154
155 <tscreen><verb>
156
157 #include <gtk/gtk.h>
158
159
160 /* E' una funzione di ritorno (callback). Gli argomenti passati sono ignorati in questo 
161 * esempio.
162 * Piu' informazioni sulle callback in seguito. */
163
164 void hello (GtkWidget *widget, gpointer data)
165 {
166     g_print ("Hello World\n");
167 }
168
169 gint delete_event(GtkWidget *widget, gpointer data)
170   {
171       g_print ("delete event occured\n");
172       /* Se si d&agrave; TRUE al manipolatore del segnale ``delete_event'', GTK emettera' il segnale
173         ``destroy''. Fornire FALSE significa non volere che la finestra sia distrutta. 
174          Cambia FALSE con TRUE e la finestra principale sara' distrutta con un "delete_event"
175       */
176
177 /* Un'altra callback */
178 void destroy (GtkWidget *widget, gpointer data)
179 {
180     gtk_main_quit ();
181 }
182
183 int main (int argc, char *argv[])
184 {
185     /* GtkWidget e' il tipo di dato per i Widget */
186     GtkWidget *window;
187     GtkWidget *button;
188     
189     /* Questa e' una chiamata presente in tutte le applicazioni GTK. Gli argomenti della
190         linea di comando vengono scorsi e restituiti alla applicazione  */
191     gtk_init (&amp;argc, &amp;argv);
192     
193     /* Crea una nuova finestra */
194     window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
195     
196     /* Quando alla finestra viene passato il segnale ``delete_event'' (questo 
197      * segnale viene passato Windows Manager di solito con l'opzione 'close' 
198      * o con la barra del titolo (title bar)) noi chiediamo che la funzione 
199      * delete_event() (definita sopra) venga invocata.
200      * Il dato passato come argomento alla funzione di ritorno &eacute; NULL
201      * ed &eacute; ignorato dalla funzione stessa. */
202     gtk_signal_connect (GTK_OBJECT (window), "delete_event",
203                         GTK_SIGNAL_FUNC (destroy), NULL);
204     
205     /* Qui connettiamo l'evento ``destroy'' al gestore del segnale.
206      * Questo evento accade quando noi chiamimo la funzione gtk_widget_destroy() 
207      * sulla finestra o se ritorniamo TRUE dalla callback ``delete_event''. */
208     gtk_signal_connect (GTK_OBJECT (window), "destroy",
209                         GTK_SIGNAL_FUNC (destroy), NULL);
210
211     /* Setta il bordo interno della finestra */
212     gtk_container_border_width (GTK_CONTAINER (window), 10);
213     
214     /* Crea un nuovo bottone avente etichetta (label)  uguale a ``Hello World'' */
215     button = gtk_button_new_with_label ("Hello World");
216     
217     /* Quando il bottone riceve il segnale ``clicked'', invochera' la funzione 
218      * hello() passando NULL come argomento della funzione. La funzione
219      * hello() &eacute; definita sopra. */
220     gtk_signal_connect (GTK_OBJECT (button), "clicked",
221                         GTK_SIGNAL_FUNC (hello), NULL);
222     
223     /* Questo far&agrave; s&igrave; che la finestra venga distrutta dalla chiamata
224      * gtk_widget_destroy(window) quando il bottone verr&agrave; premuto. Ancora,
225      * questo segnale (``destroy'') puo' arrivare da qui o dal windows 
226      * manager */
227     gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
228                                GTK_SIGNAL_FUNC (gtk_widget_destroy),
229                                GTK_OBJECT (window));
230     
231     /* Questo inserisce il bottone nella finestra 
232      * (un contenitore GTK) */
233     gtk_container_add (GTK_CONTAINER (window), button);
234     
235     /* Il passo finale &eacute; il mostrare questo nuovo widget appena creato */
236     gtk_widget_show (button);
237     
238     /* e la finestra */
239     gtk_widget_show (window);
240     
241     /* Tutte le applicazioni GTK devono avere la funzione gtk_main(). 
242      * Il controllo finisce qui e attende un evento (come la pressione
243      * di un tasto o l'evento di un mouse).
244     gtk_main ();
245     
246     return 0;
247 }
248 </verb></tscreen>
249
250 <sect1>Compilare hello World
251 <p>
252 Per compilare si utilizza :
253
254 <tscreen><verb>
255 gcc -Wall -g helloworld.c -o hello_world -L/usr/X11R6/lib \
256     -lglib -lgdk -lgtk -lX11 -lXext -lm
257 </verb></tscreen>
258 <p>
259 Le librerie sopra (glib, gtk,...) devono essere tutte nel percorso predefinito
260 delle librerie. Se cosi' non fosse aggiungi ``-L&lt;directory&gt;'' e il gcc 
261 guarder&agrave; in questa directory per cercare le librerie di cui necessita.
262 Per esempio sul mio sistema debian-linux io ho dovuto aggiungere 
263 <tt>-L/usr/X11R6/lib</> per riuscire a far trovare le librerie di X11.
264
265 <p>
266 L'odine della dichiarazione delle librerie &eacute; significativo. Il linker 
267 sa quali funzioni di una libreria ha bisogno prima di processarla.
268
269 <p>
270 le librerie che noi linkiamo sono:
271 <itemize>
272 <item> la libreria glib (-lglib), contiene varie funzioni, ma solo 
273 g_print() &eacute; usato in questo esempio. GTK si appoggia a questa
274 libreria cosi' devi sempre, comunque, linkarla. Vedi comunque la <ref 
275 id="sec_glib" name="glib"> sezione sulla glib per altri dettagli.
276 <item>La libreria GDK (-lgdk), la copertura della X11.
277 <item>La libreria GTK (-lgtk), la libreria dei widget, basata sulla GDK.
278 <item>La libreria xlib(-lX11) la quale &egrave; usata dalla GDK.
279 <item>La libreria Xext(-lXext). Questa contiene il codice per le pixmap a
280 memoria condivisa e altre estensioni di X.
281 <item>La libreria matematica (-lm). Questa &eacute; usata dalla GTK per vari scopi.
282 </itemize>
283
284 <sect1>Teoria dei segnali e delle funzioni di ritorno (callback)
285 <p>
286 Prima di guardare in dettaglio ``Hello World'', discuteremo gli eventi e le 
287 funzioni di ritorno. GTK  &egrave; un toolkit guidato dagli eventi, il che significa
288 che se ne star&agrave; a dorimire in gtk_main finch&eacute; non succeder&agrave; un evento ed il
289 controllo passer&agrave; alla funzione appropriata.
290
291 <p>
292 Questo passaggio di controllo &egrave; fatto usando l'idea dei segnali. Quando succede un 
293 evento, come la pressione di un bottone del mouse, verr&agrave; emesso il segnale appropriato 
294 dal widget che &eacute; stato premuto.
295 Questo &egrave; il modo in cui GTK fa molto del suo utile lavoro. Per fare s&igrave; che un 
296 bottone esegua una azione, noi prepareremo un gestore del segnale che catturi 
297 questi segnali e chiami la funzione corretta. Questo &egrave; fatto usando una 
298 funzione del tipo:
299
300 <tscreen><verb>
301 gint gtk_signal_connect (GtkObject *object,
302                          gchar *name,
303                          GtkSignalFunc func,
304                          gpointer func_data);
305 </verb></tscreen>
306
307 <p>
308 Dove, il primo argomento &egrave; il widget che emetter&agrave; il segnale, il secondo &egrave; il nome
309 del segnale che si vuole catturare,il terzo &egrave; la funzione che verr&agrave; invocata
310 quando il segnale sar&agrave; catturato e il quarto &egrave; il dato che potr essere passato a 
311 questa funzione.
312
313 <p>
314 La funzione specificata come terzo argomento &egrave; chiamata ``funzione di ritorno (callback)'',
315 e dovrebbe essere della forma:
316
317 <tscreen><verb>
318 void callback_func(GtkWidget *widget, gpointer *callback_data);
319 </verb></tscreen>
320 <p>
321 Dove il primo argomento sar&agrave; un puntatore al widget che emette il segnale e il
322 secondo un puntatore al dato passato come ultimo argomento della funzione 
323 gtk_signal_connect() come descritto sopra.
324
325 <p>
326 Un'altra chiamata usata nell'esempio Hello World &egrave;:
327
328 <tscreen><verb>
329 gint gtk_signal_connect_object (GtkObject *object,
330                                 gchar  *name,
331                                 GtkSignalFunc func,
332                                 GtkObject *slot_object);
333 </verb></tscreen>
334 <p>
335 gtk_signal_connect_object() &egrave; uguale a gtk_signal_connect() eccetto che la 
336 funzione di callback usa solo un argomento, un puntatore ad un'oggetto GTK.
337 Cosi' quando usa questa funzione per connettere i segnali, la callback 
338 potrebbe essere della forma :
339
340 <tscreen><verb>
341     void callback_func (GtkObject *object);
342 </verb></tscreen>
343 <p>
344 Dove object &egrave; di solito un widget. Noi, generalmente, non assegnamo una callback per 
345 gtk_signal_connect_object.  Queste sono invocate ,usualmente, per chiamare 
346 una funzione GTK che accetta un widget singolo o un oggetto come argomento, 
347 come nel caso dell'esempio Hello World.
348
349 Lo scopo di avere due funzioni per connettere i segnali &egrave; semplicemente quello di 
350 permettere alla funzione di callback di avere un numero di argomenti diverso.
351 Molte funzioni della libreria GTK accettano solo un singolo puntatore ad un widget
352 GTK come argomento, cos&igrave; per queste si pu&ograve; usare la funzione gtk_signal_connect_object(),
353 mentre per le vostre funzioni potreste aver bisogno di passare dati supplementari alle
354 funzioni di ritorno.
355
356 <sect1>Attraverso Hello World passo per passo
357 <p>
358 Ora che conosciamo la teoria che vi &egrave; dietro, iniziamo ad essere pi&ugrave; chiari 
359 camminando attraverso il programma di Hello World.
360
361 <p>
362 Questa &egrave; la funzione di callback che sar&agrave; invocata quando il bottone &egrave; clickato.
363 Noi, in questo esempio, ignoriamo sia il widget che i dati passati, ma non &egrave; 
364 difficile farci invece qualcosa. Il prossimo esempio user&agrave; l'argomento passato
365 per dire quale bottone &egrave; stato premuto.
366
367 <tscreen><verb>
368 void hello (GtkWidget *widget, gpointer *data)
369 {
370     g_print ("Hello World\n");
371 }
372 </verb></tscreen>
373
374 <p>
375 Questa callback &egrave; un po' speciale. L'evento ``delete'' avviene quanto il Window Manager
376 manda questo evento all'applicazione. Qui abbiamo una scelta da fare: cosa fare di questo evento. 
377 Possiamo ignorarlo, creare qualche tipo di risposta, o semplicemente terminare 
378 l'applicazione.
379
380 Il valore che si restituisce in questa callback fa s&igrave; che la GTK sappia cosa fare.
381 Restituire FALSE significa che noi non vogliamo che il segnale ``destroy'' sia emesso,
382 quindi far s&igrave; che la nostra applicazione continui a procedere. Ritornare TRUE vuole dire
383 far emettere il segnale ``destroy'' il quale chiamer&agrave; il gestore del segnale ``destroy''
384 (o meglio : la nostra funzione di callback).
385
386 <tscreen><verb>
387        gint delete_event(GtkWidget *widget, gpointer data)
388        {
389            g_print ("delete event occured\n");
390
391            return (FALSE);
392        }
393 </verb></tscreen>
394
395 <p>
396 Questa &egrave; un'altra funzione di callback la quale fa uscire dal programma chiamando
397 gtk_main_quit(). Non c'&egrave; molto da dire al riguardo, &egrave; abbastanza auto-esplicativa.
398
399 <tscreen><verb>
400 void destroy (GtkWidget *widget, gpointer *data)
401 {
402     gtk_main_quit ();
403 }
404 </verb></tscreen>
405 <p>
406 Ritengo che conosciate la funzione main()... si, come tutte le altre applicazioni
407 anche le applicazioni GTK hanno questa funzione.
408
409 <tscreen><verb>
410 int main (int argc, char *argv[])
411 {
412 </verb></tscreen>
413
414 <p>
415 Questa parte dichiara un puntatore ad una struttura di tipo GtkWidget. Queste sono
416 usate sotto per creare una finestra ed un bottone.
417
418 <tscreen><verb>
419     GtkWidget *window;
420     GtkWidget *button;
421 </verb></tscreen>
422 <p>
423 Qui vi &egrave; ancora la nostra gtk_init. Come prima questa inizializza il toolkit e 
424 analizza gli argomenti trovati nella linea di comando_ Tutti gli argomenti riconosciuti
425 nella linea di comando sono rimossi dalla lista degli argomenti e vengono cos&igrave; modificati 
426 argc e argv per far s&igrave; che sembri che questi non siano mai esisitie permettere alla
427 tua applicazione di analizzare gli argomenti rimasti.
428
429 <tscreen><verb>
430     gtk_init (&amp;argc, &amp;argv);
431 </verb></tscreen>
432 <p>
433 Crea una nuova finestra. Questo viene spiegato abbastanza approfonditamente pi&ugrave; avanti.
434 Viene allocata la memoria per la struttura GtkWidget *window cos&igrave; che si punti ad una struttura
435 valida. In questo modo si predispone la nuova finestra, ma non la si visualizza fino a sotto dove, quasi
436 alla fine del nostro programma, invochiamo gtk_widget_show(window).
437 <tscreen><verb>
438     window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
439 </verb></tscreen>
440 <p>
441 Questo &egrave; un esempio di come connettere un gestore dei segnali con un oggetto, in questo
442 caso la finestra. Qui viene catturato il segnale ``destroy''. Questo &egrave; emesso quando usiamo
443 il Window Manager per uccidere la finestra (e noi restituiamo TRUE dal gestore di ``delete_event'')
444 o quando emettiamo la chiamata gtk_widget_destroy() passando l'oggetto finestra 
445 come oggetto da distruggere. Sistemando le cose cos&igrave;, trattiamo entrambi i casi con una singola 
446 chiamata. Qui &egrave; giusto invocare la funzione destroy() definita sopra con NULL come argomento,
447 la quale termina l'applicazione GTK per noi.
448 Questo ci permetter&agrave; di utilizzare il Window Manager per uccidere il programma.
449 <!-- fino a qui -->
450 <p>
451 GTK_OBJECT e GTK_SIGNAL_FUNC sono macro che interpretano il casting e il controllo di tipo per noi,
452 cos&igrave; da rendere piu' leggibile il codice.
453
454 <tscreen><verb>
455     gtk_signal_connect (GTK_OBJECT (window), "destroy",
456                         GTK_SIGNAL_FUNC (destroy), NULL);
457 </verb></tscreen>
458 <p>
459 La prossima funzione &egrave; usata per settare un attributo di un oggetto contenitore. Questo
460 sistema la finestra cos&igrave; da avere un'area vuota all'interno della finestrra larga 10 pixel dove
461 non potr&agrave; andare nessun widget. Ci sono altre funzioni simili che vedremo nella
462 sezione <ref id="sec_setting_widget_attributes" name="Settare gli attributi del Widget.">
463
464 <p>
465 E ancora, GTK_CONTAINER &egrave; una macro per interpretare il casting di tipo.
466
467 <tscreen><verb>
468     gtk_container_border_width (GTK_CONTAINER (window), 10);
469 </verb></tscreen>
470 <p>
471 Questa chiamata crea un nuovo bottone. Alloca spazio in memoria per un nuovo GtkWidget,
472 inizializzandolo e facendo s&igrave; che il puntatore a bottone punti ad esso.
473 Quando sar&agrave; visualizzato, avr&agrave; etichetta  ``Hello World''.
474
475 <tscreen><verb>
476     button = gtk_button_new_with_label ("Hello World");
477 </verb></tscreen>
478 <p>
479 Qui prendiamo il bottone e gli facciamo fare qualcosa di utile.
480 Gli colleghiamo un un gestore di segnale  in modo che quando emetter&agrave; il 
481 segnale ``clicked'', verr&agrave; invocata la nostra funzione hello(). Il dato passato
482 alla funzione &egrave; ignorato, cosicch&eacute; alla funzione di callback hello() passiamo
483 semplicemente NULL. Evidentemente il segnale ``clicked'' viene emesso quando 
484 premiamo il bottone con il mouse.
485
486 <tscreen><verb>
487     gtk_signal_connect (GTK_OBJECT (button), "clicked",
488                         GTK_SIGNAL_FUNC (hello), NULL);
489 </verb></tscreen>
490 <p>
491 Usiamo questo bottone anche per uscire dal programma. Questo illustrera' 
492 come il segnale ``destroy'' pu&ograve; arrivare sia dal Window Manager che dal nostro programma. 
493 Quando il bottone &egrave; ``clicked'', come sopra, chiamera' la funzione di callback
494 hello() e poi questa nell'ordine in cui sono definite. Si possono avere
495 tante funzioni di callback, quante sono necessarie, e saranno eseguite nell'ordine in cui 
496 sono connesse. Visto che la funzione gtk_widget_destroy() accetta come argomento solo un 
497 GtkWidget *widget, usiamo la funzione gtk_signal_connect_object()
498 al posto della semplice gtk_signal_connect().
499
500 <tscreen><verb>
501     gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
502                                GTK_SIGNAL_FUNC (gtk_widget_destroy),
503                                GTK_OBJECT (window));
504 </verb></tscreen>
505 <p>
506 Questa &eacute; una chiamata di ``impacchettamento'' che sar&agrave; spiegata pi&ugrave; avanti. 
507 Ma &egrave; molto facile da capire. Semplicemente dice alla libreria GTK che il 
508 bottone &egrave; da mettere nella finestra dove sar&agrave; visualizzato.
509
510 <tscreen><verb>
511     gtk_container_add (GTK_CONTAINER (window), button);
512 </verb></tscreen>
513 <p>
514 A questo punto abbiamo predisposto tutto quello che ci eravamo prefissati.
515 Con tutti i gestori di segnale a posto e il bottone messo nella finestra in cui
516 dovrebbe essere, possiamo dire a GTK di mostrare gli oggetti sullo schermo. 
517 L'oggetto finestra viene mostrato per ultimo cos&igrave; che la finestra completa di tutti
518 i suoi oggetti sar&agrave; mostrata in una volta sola, invece di vedere
519 prima la finestra spoglia e poi la comparsa del bottone all'interno di essa.
520 Per quanto, con questi semplici esempi, questo l'avrai gi&agrave; notato.
521 <tscreen><verb>
522     gtk_widget_show (button);
523
524     gtk_widget_show (window);
525 </verb></tscreen>
526 <p>
527 E naturalmente chiamiamo gtk_main(), la quale aspetta l'arrivo degli eventi 
528 dal server X e chiamer&agrave; l'oggetto interessato per fargli emettere il segnale
529 adeguato.
530 <tscreen><verb>
531     gtk_main ();
532 </verb></tscreen>
533 E il return finale. Il controllo ritorna qui dopo che viene invocata gtk_quit().
534
535 <tscreen><verb>
536     return 0;
537 </verb></tscreen>
538 <p>
539 Ora, quando premiamo il bottone del mouse su un bottone GTK, questo oggetto
540 emette il segnale ``clicked''. Per poter utilizzare queste informazioni, il nostro
541 programma predispone un gestore di segnale per catturare quel segnale, il quale 
542 avvia la funzione da noi scelta. Nel nostro esempio, quando il bottone creato viene 
543 clickato , la funzione hello() &egrave; invocata con un argomento NULL, dopoodich&eacute;
544 viene invocato il successivo gestore di questo segnale. Questo chiama la funziona 
545 gtk_widget_destroy(), passandole l'oggetto-finestra (window) come argomento, che 
546 distrugger&agrave; la finestra. Questo fa s&igrave; che la finestra emetta il segnale
547 ``destroy'' che viene catturato e che fa invocare la funzione di ritorno 
548 destroy(), che semplicemente esce dal programma GTK.
549
550 <p>
551 Un'altro modo in cui possono andare le cose &egrave; l'uso del window manager per uccidere
552 la finestra. Questo causera' l'emissione del segnale ``delete_event'' che
553 automaticamente chiamer&agrave; il gestore del segnale ``delete_event''. Se qui noi
554 restituiamo il valore FALSE, la finestra non verr&agrave; toccata e tutto proceder&agrave; come
555 se nulla fosse successo. Dare invece il valore TRUE causer&agrave; l'emissione da parte
556 di GTK del segnale ``destroy'' il quale, a sua volta, invocher&agrave; la callback ``destroy'',
557 uscendo dall'applicazione.
558
559 <p>
560 Nota che questi segnali non sono gli stessi del sistema Unix e che non sono
561 implementati usando quei segnali, anche se la terminologia &egrave; praticamente identica.
562
563 <sect>Proseguiamo
564 <p>
565 <sect1>Tipi di Dato
566 <p>
567 Ci sono alcune cose che avrete probabilmente notato nei precedenti esempi che
568 hanno bisogno di una spiegazione. I gint, gchar ecc. che vedete sono tipi di dato
569 riferiti rispettivamente a int e char. Questo viene fatto per rimediare alla brutta
570 dipendenza dalle dimensioni di semplici tipi di dato quando si fanno dei calcoli.
571 Un buon esempio &egrave; ``gint32'' il quale sar&agrave; un tipo di dato riferito ad un intero a
572 32 bit per tutte le piattaforme x86 e ad un 64 bit per gli alpha.
573 I tipi di dato sono ben spiegati pi&ugrave; avanti ed intuitivi. Sono definiti in
574 glib/glib.h (il quale viene incluso da gtk.h).
575
576 <p>
577 Noterete anche la possibilit&agrave; di utilizzare un GtkWidget quando la funzione richiede
578 un GtkObject. GTK &egrave; una libreria orienta agli oggetti ed un widget &egrave; un oggetto.
579
580 <sect1>Altri Dettagli sui Segnali
581 <p>
582 Diamo un'altra occhiata alla dichiarazione della funzione gtk_signal_connect.
583
584 <tscreen><verb>
585 gint gtk_signal_connect (GtkObject *object, gchar *name,
586                          GtkSignalFunc func, gpointer func_data);
587 </verb></tscreen>
588 Notate il valore di ritorno definito come gint? questo &egrave; un identificatore per
589 la tua funzione di callback. Come detto sopra, si possono avere pi&ugrave; funzioni di 
590 ritorno per ogni segnale e per ogni ogetto a seconda delle necessit&agrave;. ed ognuna sar&agrave;
591 eseguita in sequenza, nell'ordine in cui sono state collegate. Questo identificatore
592 ti permette di rimuovere una funzione dalla lista delle funzioni di ritorno tramite
593 la seguente chiamata
594 <tscreen><verb>
595 void gtk_signal_disconnect (GtkObject *object,
596                             gint id);
597 </verb></tscreen>
598 Cos&igrave; passando il widget da cui vuoi rimuovere il gestore di segnale, e
599 l'identificativo restituito da una delle funzioni signal_connect, puoi rimuovere
600 il gestore di segnale che desideri da quella del widget.
601
602 <p>
603 Un'altra funzione per rimuovere tutti i segnali di un widget in una volta sola &egrave;:
604
605 <tscreen><verb>
606 gtk_signal_handlers_destroy (GtkObject *object);
607 </verb></tscreen>
608 <p>
609 Questa chiamata &egrave; abbastanza auto esplicativa. Semplicemente rimuove tutti i segnali
610 collegati al widget che passi alla funzione come argomento.
611
612 <sect1>Miglioriamo Hello World
613
614 <p>
615 Diamo un'occhiata ad una migliorata versione di Hello World con altri esempi sulle
616 callback. Questo anche ci introdurr&agrave; al nostro prossimo argomento,
617 l'impacchettamento dei widget.
618
619 <tscreen><verb>
620 #include <gtk/gtk.h>
621
622 /* La nostra funzione di callback migliorata. I dati passati a questa
623  * vengono stampati su stdout. */
624 void callback (GtkWidget *widget, gpointer *data)
625 {
626     g_print ("Hello again - %s was pressed\n", (char *) data);
627 }
628
629 /* Un'altra callback */
630 void delete_event (GtkWidget *widget, gpointer *data)
631 {
632     gtk_main_quit ();
633 }
634
635 int main (int argc, char *argv[])
636 {
637     /* GtkWidget e' il tipo di dato per i widget */
638     GtkWidget *window;
639     GtkWidget *button;
640     GtkWidget *box1;
641
642     /* Questa funzione e' invocata in tutte le applicazioni GTK, gli 
643        argomenti sono analizzati e restituiti all'applicazione. */
644     gtk_init (&amp;argc, &amp;argv);
645
646     /* Crea una nuova finestra */
647     window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
648
649     /* Questa e' una nuova chiamata. Assegna "Hello Buttons" come titolo 
650        della nostra finestra */
651     gtk_window_set_title (GTK_WINDOW (window), "Hello Buttons!");
652
653     /* Qui settiamo il gestore per il segnale "delete_event" che
654        immediatamente esce dalla applicazione.
655     gtk_signal_connect (GTK_OBJECT (window), "delete_event",
656                         GTK_SIGNAL_FUNC (delete_event), NULL);
657
658
659     /* predispone il bordo della finestra */
660     gtk_container_border_width (GTK_CONTAINER (window), 10);
661
662     /* creiamo una scatola dove mettere tutti i widget. Questa &egrave; descritta
663        dettagliatamente nella sezione "packing". La scatola non &egrave; realmente
664        visibile, &egrave; solamente usata per sistemare i widget. */
665     box1 = gtk_hbox_new(FALSE, 0);
666
667     /* Inseriamo la scatola nella finestra */
668     gtk_container_add (GTK_CONTAINER (window), box1);
669
670     /* Creiamo un nuovo bottone con etichetta "Button 1" */
671     button = gtk_button_new_with_label ("Button 1");
672
673     /* Quando il bottone e' premuto, noi invocheremo la funzione di callback,
674        con un puntatore alla stringa "button 1" come proprio argomento) */
675     gtk_signal_connect (GTK_OBJECT (button), "clicked",
676                         GTK_SIGNAL_FUNC (callback), (gpointer) "button 1");
677
678     /* invece di aggiungerlo alla finestra, lo inseriamo nella scatola invisibile,
679        la quale e' stata inserita nella finstra. */
680     gtk_box_pack_start(GTK_BOX(box1), button, TRUE, TRUE, 0);
681
682     /* Ricordati sempre questo passo. Dice a GTK che la preparazione di questo 
683        bottone e' finita e che quindi puo' essere mostrato. */
684     gtk_widget_show(button);
685
686     /* Facciamo la stessa cosa per il secondo bottone. */
687     button = gtk_button_new_with_label ("Button 2");
688
689     /* Chiamiamo la stessa funzione ma passandogli un argomento differente,
690        gli passiamo un puntatore alla stringa "button 2" */
691     gtk_signal_connect (GTK_OBJECT (button), "clicked",
692                         GTK_SIGNAL_FUNC (callback), (gpointer) "button 2");
693
694     gtk_box_pack_start(GTK_BOX(box1), button, TRUE, TRUE, 0);
695
696     /* L'ordine nel quale i bottoni sono visualizzati non e' realmente importante,
697        ma io ti raccomando di mostrare per ultima la finestra cosi' che tutto 
698        sia visualizzato in una volta sola */
699     gtk_widget_show(button);
700
701     gtk_widget_show(box1);
702
703     gtk_widget_show (window);
704
705     /* e ora ci mettiamo in gtk_main e aspettiamo che il diverimento inizi.
706     gtk_main ();
707
708     return 0;
709 }
710 </verb></tscreen>
711 <p>
712 Compilate questo programma usando gli stessi argomenti di link del nostro primo
713 esempio. Noterete che questa volta non c'&egrave; un modo semplice per uscire dal programma,
714 si deve usare il nostro window manager o la linea di comando per uccidere
715 l'applicazione.
716 Un buon esercizio per il lettore &egrave; quello di inserire un tezo bottone ``quit'' che
717 faccia uscire dal programma. Potete anche divertirvi  con le opzioni di
718 gtk_box_pack_start() mentre leggete il prossimo capitolo. Provate a ridimensionare
719 la finestra ed a osservare cosa succede.
720
721 <p>
722 Solo una piccola nota, c'&egrave; un'altra definizione di gtk_window_new() - 
723 GTK_WINDOW_DIALOG. Questa interagisce con il window manager in un modo un po' 
724 diverso, e dovrebbe essere usata per finestre temporanee.
725
726 <sect>Come ``Impacchettare'' i Widget 
727 <p>
728 Nel momento in cui si crea un'applicazione, normalmente si avr&agrave; la necessit&agrave; di mettere pi&ugrave;
729 di un unico bottone all'interno di una finestra. Il nostro primo esempio ``Hello World'' 
730 usava un solo oggetto, cosicch&eacute; abbiamo potuto usare semplicemente una chiamata
731 a gtk_container_add per impacchettare il widget nella finestra. Quando invece si vuole
732 inserire pi&ugrave; di un unico widget in una finestra, come si fa a controllare dove vengono
733 posizionati i propri oggetti? E' qui che entra in gioco il meccanismo dell'``impacchettamento''.
734 <sect1>Teoria delle Scatole per Impacchettamento
735 <p>
736 La maggior parte dell'impacchettamento viene effettuata creando delle scatole
737 come nell'esempio pi&ugrave; sopra. Le scatole sono dei contenitori invisibili di
738 widget che possiamo usare per imballarci i nostri oggetti e che esistono in
739 due variet&agrave;: in particolare si possono avere scatole orizzontali (hbox) e 
740 verticali (vbox).
741 Quando si impacchentano degli oggetti in una scatola orizzontale, gli oggetti vengono inseriti
742 orizzontalmente da sinistra a destra oppure da destra a sinistra a seconda della
743 chiamata di funzione che si usa. In una scatola verticale, gli oggetti vengono inseriti
744 dall'alto in basso o viceversa. Si pu&ograve; usare qualsiasi combinazione di scatole
745 all'interno o a fianco di altre scatole, fino ad ottenere l'effetto desiderato.
746 <p>
747 Per creare una nuova scatola orizzontale, si usa una chiamata a gtk_hbox_new(), mentre
748 per le scatole verticali si usa gtk_vbox_new(). Per inserire i widget
749 all'interno di questi contenitori si usano le funzioni gtk_box_pack_start() e
750 gtk_box_pack_end(). La funzione gtk_box_pack_start() comincer&agrave; dall'alto verso il
751 basso in una vbox e da sinistra a destra in una hbox. gtk_box_pack_end() fa l'opposto,
752 impacchettando dal basso verso l'alto in una vbox e da destra a sinistra in una hbox.
753 Queste funzioni ci permettono di giustificare a destra o a sinistra i nostri
754 widget, e possono essere mescolate in qualsiasi modo per ottenere l'effetto desiderato.
755 Useremo gtk_box_pack_start() nella maggior parte dei nostri esempi. Un oggetto pu&ograve;
756 essere costituito da un altro contenitore o da un oggetto grafico. Infatti, molti
757 oggetti grafici sono a loro volta dei contenitori, compreso il bottone, anche se
758 tipicamente all'interno del bottone mettiamo solo una etichetta.
759 <p>
760
761 Usando queste chiamate, GTK riesce a capire dove si vogliono piazzare i propri
762 widget, in modo di essere poi in grado di effettuare il ridimensionamento
763 automatico e altre cose interessanti. Esiste poi un insieme di opzioni che riguardano
764 il modo in cui i propri oggetti grafici dovrebbero essere impacchettati. Come
765 si pu&ograve; immaginare, questo metodo d&agrave; una buona flessibilit&agrave; nella creazione e
766 nella disposizione dei propri widget.
767 <sect1>Dettagli sulle Scatole
768 <p>
769 A causa di questa flessibilit&agrave;, le scatole per impacchettamento del GTK
770 possono, di primo acchito, creare un po' di disorientamento. Sono infatti disponibili
771 molte opzioni, e non &egrave; immediato il modo in cui si combinano l'una con l'altra.
772 Alla fine per&ograve;, si possono ottenere essenzialmente cinque diversi stili.
773
774 <p>
775 <?  
776 <IMG ALIGN="center" SRC="gtk_tut_packbox1.gif"
777 VSPACE="15" HSPACE="10" ALT="Box Packing Example Image" WIDTH="528"
778 HEIGHT="235">
779 >
780
781
782 Ogni linea contiene una scatola orizzontale (hbox) con diversi bottoni. 
783 La chiamata a  gtk_box_pack &egrave; una scorciatoia per la chiamata di impacchettamento
784 di ognuno dei bottoni nella hbox. Ognuno dei bottoni viene impacchettato nella
785 hbox nello stesso modo (cio&egrave;, con gli stessi argomenti per la funzione gtk_box_pack_start ()).
786 <p>
787 Questa &egrave; la dichiarazione della funzione gtk_box_pack_start.
788
789 <tscreen><verb>
790 void gtk_box_pack_start (GtkBox    *box,
791                          GtkWidget *child,
792                          gint       expand,
793                          gint       fill,
794                          gint       padding);
795 </verb></tscreen>
796 Il primo argomento &egrave; la scatola nella quale si stanno inscatolando i
797 widget, il secondo &egrave; il widget stesso. Gli oggetti per ora saranno 
798 bottoni, quindi quello che faremo sar&agrave; impacchettare bottoni in scatole.
799 <p>
800 L'argomento ``expand'' in  gtk_box_pack_start() o  gtk_box_pack_end() controlla
801 se gli oggetti devono essere sistemati nella scatola in modo da riempire tutto
802 lo spazio in diponibile presente nella scatola, in modo che la scatola si espanda fino
803 ad occupare tutta l'area assegnatale (valore TRUE).
804 La scatola pu&ograve; anche essere rimpiciolita in modo da contenere esattamente i
805 widget (valore FALSE). Assegnare a expand il valore FALSE permette di giustificare
806 a destra o sinistra i propri oggetti. In caso contrario, tutti gli ogetti si espandono
807 fino ad adattarsi alla scatola, e il medesimo effetto si pu&ograve; ottenere usando solo una
808 delle funzioni gtk_box_pack_start o pack_end.
809 <p>
810 L'argomento ``fill'' delle funzioni gtk_box_pack stabilisce se lo spazio disponibile
811 nella scatola deve essere allocato agli oggetti (TRUE) o se deve essere mantenuto
812 come riempimento attorno a questi oggetti (FALSE). Questo argomento ha effetto
813 solo se a expand &egrave; assegnato il valore TRUE.
814 <p>
815 Quando si crea una nuova scatola, la funzione ha questo aspetto:
816
817 <tscreen><verb>
818 GtkWidget * gtk_hbox_new (gint homogeneous,
819                           gint spacing);
820 </verb></tscreen>
821
822 L'argomento homogeneous di gtk_hbox_new (la stesso per gtk_vbox_new)
823 determina se ogni oggetto nella scatola deve avere la stessa dimensione (cio&egrave;
824 la stessa ampiezza in una hbox o la stessa altezza in una vbox).  Se &egrave; settato,
825 l'argomento expand delle routine gtk_box_pack &egrave; sempre attivato.
826 <p>
827 Qual &egrave; la differenza fra la spaziatura (che &egrave; stabilita quando la scatola
828 viene creata) e il riempimento (che viene stabilito quando gli elementi vengono
829 impacchettati)? La spaziatura viene inserita fra gli oggetti, mentre il
830 riempimento viene aggiuno a ciascuno dei lati dell'oggetti. La seguente figura
831 dovrebbe chiarire meglio questo punto:
832
833 <?
834 <IMG ALIGN="center" SRC="gtk_tut_packbox2.gif"
835 VSPACE="15" HSPACE="10" ALT="Box Packing Example Image" WIDTH="509"
836 HEIGHT="213">
837 >
838
839
840 Di seguito &egrave; riportato il codice usato per creare le immagini precedenti.
841 L'ho commentato in modo piuttosto pesante, in modo che non dovreste avere
842 problemi nel seguirlo. Compilatelo voi stessi e preovate a giocarci un po'.
843
844 <sect1>Programma Dimostrativo di Impacchettamento
845 <p>
846
847 <tscreen><verb>
848 #include "gtk/gtk.h"
849
850 void
851 delete_event (GtkWidget *widget, gpointer *data)
852 {
853     gtk_main_quit ();
854 }
855
856 /* Costruisco una nuova hbox riempita con bottoni-etichette. Gli
857  * argomenti per le varabili che ci interessano sono passati
858  * in questa funzione. Non mostriamo la scatola, ma mostriamo
859  * tutto quello che c'&egrave; dentro. */
860 GtkWidget *make_box (gint homogeneous, gint spacing,
861                      gint expand, gint fill, gint padding) 
862 {
863     GtkWidget *box;
864     GtkWidget *button;
865     char padstr[80];
866     
867     /* costruisco una nuova hbox con i valori appropriati di
868      * homogeneous e spacing */
869     box = gtk_hbox_new (homogeneous, spacing);
870     
871     /* costruisco una serie di bottoni con i valori appropriati */
872     button = gtk_button_new_with_label ("gtk_box_pack");
873     gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
874     gtk_widget_show (button);
875     
876     button = gtk_button_new_with_label ("(box,");
877     gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
878     gtk_widget_show (button);
879     
880     button = gtk_button_new_with_label ("button,");
881     gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
882     gtk_widget_show (button);
883     
884     /* costruisco un bottone con l'etichetta che dipende dal valore di 
885      * expand. */
886     if (expand == TRUE)
887             button = gtk_button_new_with_label ("TRUE,");
888     else
889             button = gtk_button_new_with_label ("FALSE,");
890     
891     gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
892     gtk_widget_show (button);
893     
894     /* Questo &egrave; la stessa cosa della creazione del bottone per "expand"
895      * pi&ugrave; sopra, ma usa la forma breve. */
896     button = gtk_button_new_with_label (fill ? "TRUE," : "FALSE,");
897     gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
898     gtk_widget_show (button);
899     
900     sprintf (padstr, "%d);", padding);
901     
902     button = gtk_button_new_with_label (padstr);
903     gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
904     gtk_widget_show (button);
905     
906     return box;
907 }
908
909 int
910 main (int argc, char *argv[])
911 {
912     GtkWidget *window;
913     GtkWidget *button;
914     GtkWidget *box1;
915     GtkWidget *box2;
916     GtkWidget *separator;
917     GtkWidget *label;
918     GtkWidget *quitbox;
919     int which;
920     
921     /* La nostra inizializzazione, non dimenticatela! :) */
922     gtk_init (&amp;argc, &amp;argv);
923     
924     if (argc != 2) {
925         fprintf (stderr, "uso: packbox num, dove num &egrave; 1, 2, o 3.\n");
926         /* questo fa solo un po' di pulizia in GTK, ed esce con un valore 1. */
927         gtk_exit (1);
928     }
929     
930     which = atoi (argv[1]);
931
932     /* Creiamo la nostra finestra */
933     window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
934
935     /* Ci si dovrebbe sempre ricordare di connettere il segnale di destroy
936      * alla finestra principale. Ci&ograve; &egrave; molto importante per avere un funzionamento
937      * corretto dal punto di vista intuitivo */
938     gtk_signal_connect (GTK_OBJECT (window), "delete_event",
939                         GTK_SIGNAL_FUNC (delete_event), NULL);
940     gtk_container_border_width (GTK_CONTAINER (window), 10);
941     
942     /* Creiamo una scatola verticale (vbox) in cui impacchettare quelle
943      * orizzontali. Questo ci permette di impilare le scatole orizzontali
944      * piene di bottoni una sull'altra in questa vbox. */
945   
946     box1 = gtk_vbox_new (FALSE, 0);
947     
948     /* Decide quale esempio si deve mostrare. Corrispondono alle figure precedenti */
949     switch (which) {
950     case 1:
951         /* creare una nuova etichetta. */
952         label = gtk_label_new ("gtk_hbox_new (FALSE, 0);");
953         
954         /* allineare l'etichetta al lato sinistro. Discuteremo questa e altre
955          * funzioni nella sezione dedicata agli attributi degli oggetti grafici. */
956         gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
957
958         /* Impacchettare l'etichetta nella scatola verticale (vbox box1).
959          * Ricordare che gli oggetti che vengono aggiunti in una vbox vengono
960          * impacchettati uno sopra all'altro in ordine. */
961         gtk_box_pack_start (GTK_BOX (box1), label, FALSE, FALSE, 0);
962         
963         /* mostrare l'etichetta */
964         gtk_widget_show (label);
965         
966         /* chiamare la nostra funzione make_box - homogeneous = FALSE,
967          * spacing = 0, expand = FALSE, fill = FALSE, padding = 0 */
968         box2 = make_box (FALSE, 0, FALSE, FALSE, 0);
969         gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
970         gtk_widget_show (box2);
971
972         /* chiamare la nostra funzione make_box - homogeneous = FALSE, spacing = 0,
973          * expand = FALSE, fill = FALSE, padding = 0 */
974         box2 = make_box (FALSE, 0, TRUE, FALSE, 0);
975         gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
976         gtk_widget_show (box2);
977         
978         /* Gli argomenti sono: homogeneous, spacing, expand, fill, padding */
979         box2 = make_box (FALSE, 0, TRUE, TRUE, 0);
980         gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
981         gtk_widget_show (box2);
982         
983         /* Questo crea un separatore. Li conosceremo meglio in seguito, 
984          * comunque sono piuttosto semplici. */
985         separator = gtk_hseparator_new ();
986         
987         /* Impacchetta il separatore nella vbox. Ricordare che stiamo impacchettando
988          * ognuno di questi oggetti in una vbox, cosicch&eacute; essi verranno
989          * impacchettati verticalmente. */
990         gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5);
991         gtk_widget_show (separator);
992         
993         /* crea un'altra nuova etichetta e mostrala. */
994         label = gtk_label_new ("gtk_hbox_new (TRUE, 0);");
995         gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
996         gtk_box_pack_start (GTK_BOX (box1), label, FALSE, FALSE, 0);
997         gtk_widget_show (label);
998         
999         /* Gli argomenti sono: homogeneous, spacing, expand, fill, padding */
1000         box2 = make_box (TRUE, 0, TRUE, FALSE, 0);
1001         gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1002         gtk_widget_show (box2);
1003         
1004         /* Gli argomenti sono: homogeneous, spacing, expand, fill, padding */
1005         box2 = make_box (TRUE, 0, TRUE, TRUE, 0);
1006         gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1007         gtk_widget_show (box2);
1008         
1009         /* ancora un nuovo separatore. */
1010         separator = gtk_hseparator_new ();
1011         /* Gli ultimi 3 argumenti per gtk_box_pack_start sono: expand, fill, padding. */
1012         gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5);
1013         gtk_widget_show (separator);
1014         
1015         break;
1016
1017     case 2:
1018
1019         /* creare una nuova etichetta, ricordare che box1 &egrave; la vbox creata 
1020          * vicino all'inizio di main() */
1021         label = gtk_label_new ("gtk_hbox_new (FALSE, 10);");
1022         gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
1023         gtk_box_pack_start (GTK_BOX (box1), label, FALSE, FALSE, 0);
1024         gtk_widget_show (label);
1025         
1026         /* Gli argomenti sono: homogeneous, spacing, expand, fill, padding */
1027         box2 = make_box (FALSE, 10, TRUE, FALSE, 0);
1028         gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1029         gtk_widget_show (box2);
1030         
1031         /* Gli argomenti sono: homogeneous, spacing, expand, fill, padding */
1032         box2 = make_box (FALSE, 10, TRUE, TRUE, 0);
1033         gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1034         gtk_widget_show (box2);
1035         
1036         separator = gtk_hseparator_new ();
1037         /* Gli ultimi tre arcomenti di gtk_box_pack_start sono: expand, fill, padding. */
1038         gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5);
1039         gtk_widget_show (separator);
1040         
1041         label = gtk_label_new ("gtk_hbox_new (FALSE, 0);");
1042         gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
1043         gtk_box_pack_start (GTK_BOX (box1), label, FALSE, FALSE, 0);
1044         gtk_widget_show (label);
1045         
1046         /* Gli argomenti sono: homogeneous, spacing, expand, fill, padding */
1047         box2 = make_box (FALSE, 0, TRUE, FALSE, 10);
1048         gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1049         gtk_widget_show (box2);
1050         
1051         /* Gli argomenti sono: homogeneous, spacing, expand, fill, padding */
1052         box2 = make_box (FALSE, 0, TRUE, TRUE, 10);
1053         gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1054         gtk_widget_show (box2);
1055         
1056         separator = gtk_hseparator_new ();
1057         /* Gli ultimi tre argomenti di gtk_box_pack_start sono: expand, fill, padding. */
1058         gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5);
1059         gtk_widget_show (separator);
1060         break;
1061     
1062     case 3:
1063
1064     /* Questo dimostra la possibilit&agrave; di usare use gtk_box_pack_end() per
1065          * giustificare gli oggetti a destra. Per prima cosa creiamo una
1066
1067          * nuova scatola come prima. */
1068         box2 = make_box (FALSE, 0, FALSE, FALSE, 0);
1069         /* creiamo l'etichetta che sar&agrave; aggiunta alla fine. */
1070         label = gtk_label_new ("end");
1071         /* impacchettiamola usando gtk_box_pack_end(), cos&igrave; che viene inserita
1072          * sul lato destro della hbox creata nella chiamata a the make_box(). */
1073         gtk_box_pack_end (GTK_BOX (box2), label, FALSE, FALSE, 0);
1074         /* mostriamo l'etichetta. */
1075         gtk_widget_show (label);
1076         
1077         /* impacchettiamo box2 in box1 (the vbox, ricordate? :) */
1078         gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1079         gtk_widget_show (box2);
1080         
1081         /* un separatore per il fondo */
1082         separator = gtk_hseparator_new ();
1083         /* Questo assegna esplicitamente al separatore l'ampiezza di 400 pixel
1084          * e l'altezza di 5 pixel. Ci&ograve; fa s&igrave; che la hbox che abbiamo creato sia
1085          * anche essa larga 400 pixel, e che l'etichetta finale sia separata dalle
1086          * altre etichette nella hbox. In caso contrario, tutti gli oggetti nella
1087          * hbox sarebbero impacchettati il pi&ugrave; vicino possibile. */
1088         gtk_widget_set_usize (separator, 400, 5);
1089         /* impacchetta il separatore nella vbox (box1) creata vicino all'inizio 
1090          * di main() */
1091         gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5);
1092         gtk_widget_show (separator);    
1093     }
1094     
1095     /* Creare un'altra nuova hbox.. ricordate che ne possiamo usare quante ne vogliamo! */
1096     quitbox = gtk_hbox_new (FALSE, 0);
1097     
1098     /* Il nostro bottone di uscita. */
1099     button = gtk_button_new_with_label ("Quit");
1100     
1101
1102     /* Configuriamo il segnale per distruggere la finestra.  Ricordate che
1103      * ci&ograve; mander&agrave; alla finestra il segnale "destroy", che verr&agrave; catturato 
1104      * dal nostro gestore di segnali che abbiamo definito in precedenza. */
1105     gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
1106                                GTK_SIGNAL_FUNC (gtk_widget_destroy),
1107                                GTK_OBJECT (window));
1108     /* impacchetta il bottone in quitbox.
1109      * Gli ultimi tre argomenti di gtk_box_pack_start sono: expand, fill, padding. */
1110     gtk_box_pack_start (GTK_BOX (quitbox), button, TRUE, FALSE, 0);
1111     /* impacchetta quitbox nella vbox (box1) */
1112     gtk_box_pack_start (GTK_BOX (box1), quitbox, FALSE, FALSE, 0);
1113     
1114     /* impacchetta la vbox (box1), che ora contiene tutti i nostri oggetti,
1115      * nella finestra principale. */
1116     gtk_container_add (GTK_CONTAINER (window), box1);
1117     
1118     /* e mostra tutto quel che rimane */
1119     gtk_widget_show (button);
1120     gtk_widget_show (quitbox);
1121     
1122     gtk_widget_show (box1);
1123     /* Mostriamo la finestra alla fine in modo che tutto spunti fuori assieme. */
1124     gtk_widget_show (window);
1125     
1126     /* E, naturalmente, la nostra funzione main. */
1127     gtk_main ();
1128
1129     /* Il controllo ritorna a questo punto quando viene chiamata gtk_main_quit(), 
1130      * ma non quando si usa gtk_exit. */
1131     
1132     return 0;
1133 }
1134 </verb></tscreen>
1135
1136 <p>
1137 <sect1>Impacchettamento con uso di Tabelle
1138 <p>
1139 Diamo ora un'occhiata ad un altro modo di impacchettare - le Tabelle.
1140 In certe situazioni, possono risultare estremamente utili.
1141
1142 Usando le tabelle, creiamo una griglia in cui possiamo piazzare gli oggetti.
1143 Gli oggetti possono occupare tanti spazi quanti ne specifichiamo.
1144
1145 Naturalmente, la prima cosa da vedere &egrave; la funzione gtk_table_new:
1146
1147 <tscreen><verb>
1148 GtkWidget* gtk_table_new (gint rows,
1149                           gint columns,
1150                           gint homogeneous);
1151 </verb></tscreen>
1152 <p>
1153 Il primo argomento rappresenta il numero di righe da mettere nella tabella,
1154 mentre il secondo &egrave; ovviamente il numero di colonne.
1155
1156 L'argomento homogeneous ha a che fare con il modo in cui le caselle della tabella
1157 sono dimensionate. Se homogeneous ha il valore TRUE, le caselle sono ridimensionate
1158 fino alla dimensione del pi&ugrave; grande oggetto contenuto nella tabelle. Se &egrave; FALSE, la
1159 dimensione delle caselle&egrave; decisa dal pi&ugrave; alto oggetto in una certa riga e dal pi&ugrave;
1160 largo oggetto in una stessa colonna.
1161
1162 Le righe e le colonne sono disposte a partire da 0 fino a n, dove n &egrave; il numero
1163 che era stato specificato nella chiamata a gtk_table_new. Cos&igrave;, se specificate 
1164 rows = 2 e columns = 2, lo schema avr&agrave; questo aspetto:
1165
1166 <tscreen><verb>
1167  0          1          2
1168 0+----------+----------+
1169  |          |          |
1170 1+----------+----------+
1171  |          |          |
1172 2+----------+----------+
1173 </verb></tscreen>
1174 <p>
1175 Notate che il sistema di coordinate ha origine nel vertice in alto a sinistra. Per
1176 mettere un oggetto in una tabella, usate la seguente funzione:
1177
1178 <tscreen><verb>
1179 void gtk_table_attach (GtkTable      *table,
1180                        GtkWidget     *child,
1181                        gint           left_attach,
1182                        gint           right_attach,
1183                        gint           top_attach,
1184                        gint           bottom_attach,
1185                        gint           xoptions,
1186                        gint           yoptions,
1187                        gint           xpadding,
1188                        gint           ypadding);
1189 </verb></tscreen>                                      
1190 <p>
1191 In cui il primo argomento (``table'') &egrave; la tabella che avete creato e il secondo
1192 (``child'') &egrave; l'oggetto che volete piazzare nella tabella.
1193
1194 Gli argomenti ``attach''  (right, left, top, bottom)  specificano dove mettere l'oggetto
1195 e quante caselle adoperare. Se volete mettere un bottone nella casella in basso a destra
1196 nella nostra tabella 2x2, e volete che esso riempia SOLO quella casella, dovete porre
1197 left_attach = 1, right_attach = 2, top_attach = 1, bottom_attach = 2.
1198
1199 Se invece volete che un oggetto si prenda tutta la riga pi&ugrave; in alto nella nostra tabella
1200 2x2, dovreste usare left_attach = 0, right_attach =2, top_attach = 0, 
1201 bottom_attach = 1.
1202
1203 Gli argomenti  ``xoptions'' e ``yoptions'' sono usati per specificare le opzioni di impacchettamento;
1204 di essi si pu&ograve; fare l'OR in modo di ottenere opzioni multiple.
1205
1206 Le opzioni sono:
1207 <itemize>
1208 <item>GTK_FILL - Se la parte di tabella in cui si vuole inserire il widget &egrave; pi&ugrave; 
1209 grande dell'oggetto, e se si specifica GTK_FILL, l'oggetto viene espanso fino ad
1210 occupare tutto lo spazio disponibile.
1211
1212 <item>GTK_SHRINK - Se si alloca all'oggetto nella tabella meno spazio del necessario
1213 (di solito succede quando l'utente ridimensiona la finestra), allora normalmente
1214 l'oggetto verrebbe spinto fuori dal fondo della finestra fino a sparire.
1215 Se invece si specifica GTK_SHRINK is specified, gli oggetti si rimpiccioliscono
1216 assieme alla tabella.
1217
1218 <item>GTK_EXPAND - Questo fa s&igrave; che la tabella si espanda fino ad occupare tutto lo 
1219 spazio che rimane nella finestra.
1220 </itemize>
1221
1222 Il riempimento funziona come nelle scatole, con la creazione di un'area vuota
1223 attorno all'oggetto la cui dimensione viene specificata in pixel.
1224
1225 La funzione gtk_table_attach() ha UN MUCCHIO di opzioni. Quindi, ecco una scorciatoia:
1226
1227 <tscreen><verb>
1228 void gtk_table_attach_defaults (GtkTable   *table,
1229                                 GtkWidget  *widget,
1230                                 gint        left_attach,
1231                                 gint        right_attach,
1232                                 gint        top_attach,
1233                                 gint        bottom_attach);
1234 </verb></tscreen>
1235
1236 Le xoptions e yoptions vengono posti per difetto a GTK_FILL | GTK_EXPAND, e sia xpadding
1237 che ypadding vengono posti a 0. Il resto degli argomenti sono identici a quelli della funzione
1238 precedente.
1239
1240 Ci sono poi le funzioni gtk_table_set_row_spacing() and gtk_table_set_col_spacing().
1241 Queste mettono dello spazio fra le righe (o colonne)in corrispondenza di una specifica
1242 riga (o colonna).
1243
1244 <tscreen><verb>
1245 void gtk_table_set_row_spacing (GtkTable      *table,
1246                                 gint           row,
1247                                 gint           spacing);
1248 </verb></tscreen>
1249 e
1250 <tscreen><verb>
1251 void       gtk_table_set_col_spacing  (GtkTable      *table,
1252                                        gint           column,
1253                                        gint           spacing);
1254 </verb></tscreen>
1255
1256 Notate che per le colonne lo spazio viene posto alla destra della colonna, mentre
1257 per le righe lo spazio viene posto al di sotto della riga.
1258
1259 Si pu&ograve; poi inserire una spaziatura identica fra tutte le righe e/o colonne usando:
1260
1261 <tscreen><verb>
1262 void gtk_table_set_row_spacings (GtkTable *table,
1263                                  gint      spacing);
1264 </verb></tscreen>
1265 <p>
1266 e
1267 <tscreen><verb>
1268 void gtk_table_set_col_spacings (GtkTable  *table,
1269                                  gint       spacing);
1270 </verb></tscreen>
1271 <p>
1272 Notate che con queste chiamate,  all'ultima riga e all'ultima colonna
1273 non viene assegnata alcuna spaziatura.
1274
1275 <sect1>Esempio di Impacchettamento con Tabelle
1276 <p>
1277 Per il momento, si prega di fare riferimento all'esempio di tabella in
1278 testgtk.c distribuito con i sorgenti di gtk.
1279
1280
1281 <sect>Panoramica sui Widget
1282 <p>
1283 <p>
1284 La procedura generale di creazione di un widget in GTK prevede i seguenti passi:
1285 <enum>
1286 <item> gtk_*_new - una delle varie funzioni che servono per greare un nuovo widget.
1287 In questa sezione le vedremo tutte in dettaglio.
1288
1289 <item> Connettere tutti i segnali che si vogliono usare alle funzione gestione appropriate.
1290
1291 <item> Assegnare gli attributi all'oggetto.
1292
1293 <item> Impacchettare l'oggetto in un contenitore usando la chiamate appropriata, 
1294 per esempio gtk_container_add() o gtk_box_pack_start().
1295
1296 <item> Mostrare l'oggetto con gtk_widget_show().
1297 </enum>
1298 <p>
1299 gtk_widget_show() fa s&igrave; che GTK sappia che abbiamo terminato di assegnare gli
1300 attributi dell'oggetto grafico, e che &egrave; pronto per essere visualizzato.
1301 Si pu&ograve; anche usare la funzione gtk_widget_hide per farlo sparire di nuovo.
1302 L'ordine in cui mostrate gli oggetti grafici non &egrave; importante, ma io suggerisco
1303 di mostrare per ultima la finestra, in modo che questa spunti fuori gi&agrave; completa,
1304 invece di vedere i singoli oggetti che arrivano sullo schermo a mano a mano che si
1305 formano. I figli di un oggetto grafico (anche una finestra &egrave; un oggetto grafico) non
1306 vengono infatti mostrati finch&eacute; la finestra stessa non viene mostrata usando la
1307 funzione gtk_widget_show().
1308
1309
1310 <sect1> Casting
1311 <p>
1312 Noterete andando avanti che GTK usa un sistema di casting di tipo. Questa operazione
1313 viene sempre effettuata usando delle macro che allo stesso tempo controllano la
1314 possibilit&agrave; di effettuare il cast sull'elemento dato e lo effettuano realmente.
1315 Alcune macro che avrete modo di incontrare sono:
1316
1317 <itemize>
1318 <item> GTK_WIDGET(widget)
1319 <item> GTK_OBJECT(object)
1320 <item> GTK_SIGNAL_FUNC(function)
1321 <item> GTK_CONTAINER(container)
1322 <item> GTK_WINDOW(window)
1323 <item> GTK_BOX(box)
1324 </itemize>
1325
1326 Tutte queste funzioni  sono usate per fare il cast di argomenti di funzione. Le vedrete
1327 negli esempi, e capirete se &egrave; il caso di usarle semplicemente guardando alle
1328 dichiarazioni delle funzioni.
1329
1330 Come potrete vedere pi&ugrave; sotto nella gerarchia delle classi, tutti i GtkWidgets
1331 sono derivati dalla classe base GtkObject. Ci&ograve; significa che potete usare un
1332 widget in ogni posto in cui una funzione richiede un oggetto - semplicemente
1333 usate la macro GTK_OBJECT().
1334
1335 Per esempio:
1336
1337 <tscreen><verb>
1338 gtk_signal_connect(GTK_OBJECT(button), "clicked",
1339                    GTK_SIGNAL_FUNC(callback_function), callback_data);
1340 </verb></tscreen> 
1341
1342 Questo fa il cast del bottone in un oggetto e fornisce alla chiamata di ritorno
1343 un cast al puntatore a funzione.
1344
1345 Molti oggetti grafici sono anche contenitori. Se guardate alla gerarchia delle
1346 classi pi&ugrave; sotto, vedrete che molti oggetti grafici sono derivati dalla classe
1347 GtkContainer. Ognuna di queste classi pu&ograve; essere usata, con la macro GTK_CONTAINER,
1348 come argomento per funzioni che richiedono un contenitore.
1349
1350 Sfortunatamente, in questo tutorial non si parler&agrave; in modo estensivo di queste macro,
1351 ma raccomando di dare un'occhiata ai file header di GTK. Pu&ograve; essere una cosa molto
1352 educativa. Infatti, non &egrave; difficile imparare come funziona un oggetto solo guardando
1353 le dichiarazioni delle funzioni.
1354
1355 <p>
1356 <sect1>Gerarchia degli Oggetti Grafici
1357 <p>
1358 Ecco, per vostro riferimento, la gerarchia delle classi usata per implementare gli
1359 oggetti grafici.
1360
1361 <tscreen><verb>
1362     GtkObject
1363     +-- GtkData
1364     |   \-- GtkAdjustment
1365     |
1366     \-- GtkWidget
1367         +-- GtkContainer
1368         |   +-- GtkBin
1369         |   |   +-- GtkAlignment
1370         |   |   +-- GtkFrame
1371         |   |   |   *-- GtkAspectFrame
1372         |   |   |
1373         |   |   +-- GtkItem
1374         |   |   |   +-- GtkListItem
1375         |   |   |   +-- GtkMenuItem
1376         |   |   |   |   +-- GtkCheckMenuItem
1377         |   |   |   |       *-- GtkRadioMenuItem
1378         |   |   |   |
1379         |   |   |   *-- GtkTreeItem
1380         |   |   |
1381         |   |   +-- GtkViewport
1382         |   |   \-- GtkWindow
1383         |   |       +-- GtkDialog
1384         |   |       \-- GtkFileSelection
1385         |   |
1386         |   +-- GtkBox
1387         |   |   +-- GtkHBox
1388         |   |   \-- GtkVBox
1389         |   |       +-- GtkColorSelection
1390         |   |       \-- GtkCurve
1391         |   |
1392         |   +-- GtkButton
1393         |   |   +-- GtkOptionMenu
1394         |   |   \-- GtkToggleButton
1395         |   |       \-- GtkCheckButton
1396         |   |           \-- GtkRadioButton
1397         |   |
1398         |   +-- GtkList
1399         |   +-- GtkMenuShell
1400         |   |   +-- GtkMenu
1401         |   |   \-- GtkMenuBar
1402         |   |
1403         |   +-- GtkNotebook
1404         |   +-- GtkScrolledWindow
1405         |   +-- GtkTable
1406         |   \-- GtkTree
1407         |
1408         +-- GtkDrawingArea
1409         +-- GtkEntry
1410         +-- GtkMisc
1411         |   +-- GtkArrow
1412         |   +-- GtkImage
1413         |   +-- GtkLabel
1414         |   \-- GtkPixmap
1415         |
1416         +-- GtkPreview
1417         +-- GtkProgressBar
1418         +-- GtkRange
1419         |   +-- GtkScale
1420         |   |   +-- GtkHScale
1421         |   |   \-- GtkVScale
1422         |   |
1423         |   \-- GtkScrollbar
1424         |       +-- GtkHScrollbar
1425         |       \-- GtkVScrollbar
1426         |
1427         +-- GtkRuler
1428         |   +-- GtkHRuler
1429         |   \-- GtkVRuler
1430         |
1431         \-- GtkSeparator
1432             +-- GtkHSeparator
1433             \-- GtkVSeparator
1434
1435 </verb></tscreen>
1436 <p>
1437
1438 <sect1>Oggetti senza Finestre
1439 <p>
1440 Gli oggetti seguenti non hanno una finestra associata. Se volete catturare 
1441 degli eventi, dovrete usare l'oggetto GtkEventBox. Vedete anche la sezione su
1442 <ref id="sec_The_EventBox_Widget" name="Il Widget EventBox">
1443
1444 <tscreen><verb>
1445 GtkAlignment
1446 GtkArrow
1447 GtkBin
1448 GtkBox
1449 GtkImage
1450 GtkItem
1451 GtkLabel
1452 GtkPaned
1453 GtkPixmap
1454 GtkScrolledWindow
1455 GtkSeparator
1456 GtkTable
1457 GtkViewport
1458 GtkAspectFrame
1459 GtkFrame
1460 GtkVPaned
1461 GtkHPaned
1462 GtkVBox
1463 GtkHBox
1464 GtkVSeparator
1465 GtkHSeparator
1466 </verb></tscreen>
1467 <p>
1468 Proseguiremo la nostra esplorazione di GTK esaminando uno alla volta tutti
1469 gli oggetti, creando qualche semplice funzione per mostrarli. Un'altra
1470 buona sorgente &egrave; il programma testgtk.c che viene fornito con GTK. Potete
1471 trovarlo in gtk/testgtk.c.
1472
1473 <sect>Il Widget Bottone (Button)
1474 <p>
1475 <sect1>Bottoni Normali
1476 <p>
1477 Ormai abbiamo visto tutto quello che c'&egrave; da vedere riguardo all'oggetto
1478 ``bottone''. E' piuttosto semplice, ma ci sono due modi per crare un bottone.
1479 Potete usare gtk_button_new_with_label() per creare un bottone con una
1480 etichetta, o usare gtk_button_new() per creare un bottone vuoto. In tal caso &egrave; poi
1481 vostro compito impacchettare un'etichetta o una pixmap sul bottone creato.
1482 Per fare ci&ograve;, create una nuova scatola, e poi impacchettateci i vostri
1483 oggetti usando la solita  gtk_box_pack_start, e infine usate la funzione
1484 gtk_container_add per impacchettare la scatola nel bottone.
1485 <p>
1486 Ecco un esempio di utilizzo di  gtk_button_new per creare un bottone con
1487 un'immagine ed un'etichetta su di s&egrave;. Ho separato il codice usato per
1488 creare la scatola in modo che lo possiate usare nei vostri programmi.
1489
1490 <tscreen><verb>
1491 #include <gtk/gtk.h>
1492
1493
1494 /* crea una nuova hbox contenente un'immagine ed un'etichetta
1495  * e ritorna la scatola creata. */
1496
1497 GtkWidget *xpm_label_box (GtkWidget *parent, gchar *xpm_filename, gchar *label_text)
1498 {
1499     GtkWidget *box1;
1500     GtkWidget *label;
1501     GtkWidget *pixmapwid;
1502     GdkPixmap *pixmap;
1503     GdkBitmap *mask;
1504     GtkStyle *style;
1505
1506     /* creare una scatola per una xpm ed una etichetta */
1507     box1 = gtk_hbox_new (FALSE, 0);
1508     gtk_container_border_width (GTK_CONTAINER (box1), 2);
1509
1510     /* ottengo lo stile del bottone. Penso che sia per avere il colore
1511      * dello sfondo. Se qualcuno sa il vero motivo, &egrave; pregato di dirmelo. */
1512     style = gtk_widget_get_style(parent);
1513
1514     /* e ora via con le faccende dell'xpm stuff. Carichiamo l'xpm*/
1515     pixmap = gdk_pixmap_create_from_xpm (parent->window, &amp;mask,
1516                                          &amp;style->bg[GTK_STATE_NORMAL],
1517                                          xpm_filename);
1518     pixmapwid = gtk_pixmap_new (pixmap, mask);
1519
1520     /* creiamo l'etichetta per il bottone */
1521     label = gtk_label_new (label_text);
1522
1523     /* impacchettiamo la pixmap e l'etichetta nella scatola */
1524     gtk_box_pack_start (GTK_BOX (box1),
1525                         pixmapwid, FALSE, FALSE, 3);
1526
1527     gtk_box_pack_start (GTK_BOX (box1), label, FALSE, FALSE, 3);
1528
1529     gtk_widget_show(pixmapwid);
1530     gtk_widget_show(label);
1531
1532     return (box1);
1533 }
1534
1535 /* la nostra solita funzione di callback */
1536 void callback (GtkWidget *widget, gpointer *data)
1537 {
1538     g_print ("Hello again - %s was pressed\n", (char *) data);
1539 }
1540
1541
1542 int main (int argc, char *argv[])
1543 {
1544     /* GtkWidget &egrave; il tipo per contenere gli oggetti */
1545     GtkWidget *window;
1546     GtkWidget *button;
1547     GtkWidget *box1;
1548
1549     gtk_init (&amp;argc, &amp;argv);
1550
1551     /* creiamo una nuova finestra */
1552     window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1553
1554     gtk_window_set_title (GTK_WINDOW (window), "Pixmap'd Buttons!");
1555
1556     /* E' una buona idea fare questo per tutte le finestre. */
1557     gtk_signal_connect (GTK_OBJECT (window), "destroy",
1558                         GTK_SIGNAL_FUNC (gtk_exit), NULL);
1559
1560
1561     /* assegnamo lo spessore del bordo della finestra */
1562     gtk_container_border_width (GTK_CONTAINER (window), 10);
1563
1564     /* creiamo un nuovo bottone */
1565     button = gtk_button_new ();
1566
1567     /* Ormai dovreste esservi abituati a vedere la maggior parte di
1568      * queste funzioni  */
1569     gtk_signal_connect (GTK_OBJECT (button), "clicked",
1570                         GTK_SIGNAL_FUNC (callback), (gpointer) "cool button");
1571
1572     /* questa chiama la nostra funzione di creazione di scatole */
1573     box1 = xpm_label_box(window, "info.xpm", "cool button");
1574
1575     /* impacchetta e mostra tutti i nostri oggetti */
1576     gtk_widget_show(box1);
1577
1578     gtk_container_add (GTK_CONTAINER (button), box1);
1579
1580     gtk_widget_show(button);
1581
1582     gtk_container_add (GTK_CONTAINER (window), button);
1583
1584     gtk_widget_show (window);
1585
1586     /* mettiti in gtk_main e aspetta che cominci il divertimento! */
1587     gtk_main ();
1588
1589     return 0;
1590 }
1591 </verb></tscreen>
1592 La funzione xpm_label_box pu&ograve; essere usata per impacchettare delle xpm
1593 e delle etichette su qualsiasi oggetto che pu&ograve; essere un contenitore.
1594
1595 <sect1> Bottoni a Commutazione (Toggle Buttons)
1596 <p>
1597 I bottoni a commutazione sono molto simili ai bottoni normali, tranne che per il
1598 fatto che essi si trovano sempre in uno di due stati, che si alternano ad ogni
1599 click. Possono trovarsi nello stato ``premuto'', e quando li si ripreme, tornano
1600 ad essere sollevati. Ri-clickandoli, torneranno gi&ugrave;.
1601
1602 I bottoni a commutazione sono la base per i bottoni di controllo (check button) e
1603 per i radio-bottoni, e quindi molte delle chiamate disponibili per i bottoni
1604 a commutazione vengono ereditati dai radio-bottoni e dai bottoni di controllo.
1605 Ma vedremo questi aspetti nel momento in cui li incontreremo.
1606
1607 Creare un nuovo bottone a commutazione:
1608
1609 <tscreen><verb>
1610 GtkWidget* gtk_toggle_button_new (void);
1611
1612 GtkWidget* gtk_toggle_button_new_with_label (gchar *label);
1613 </verb></tscreen>
1614 <p>
1615 Come potete immaginare, queste funzioni lavorano in modo identico che per
1616 i bottoni normali. La prima crea un bottone a commutazione vuoto e la seconda un
1617 bottone con un'etichetta.
1618 <p>
1619 Per ottenere lo stato dei widget a commutazione, compresi i radio-bottoni e i
1620 bottoni di controllo, si pu&ograve; usare una macro come mostrato nell'esempio 
1621 pi&ugrave; sotto. In questo modo lo stato dell'oggetto commutabile viene valutato in
1622 una funzione di ritorno. Il segnale emesso dai bottoni a commutazione 
1623 (toggle button, il radio button o il check button) che ci interessa &egrave; il segnale
1624 ``toggled''. Per controllare lo stato di questi bottoni, create un gestore di
1625 segnali che catturi il ``toggled'', e usate la macro per determinare
1626 il suo stato. La funzione di callback avr&agrave; un aspetto pi&ugrave; o meno cos&igrave;:
1627
1628 <tscreen><verb>
1629 void toggle_button_callback (GtkWidget *widget, gpointer   data)
1630  {
1631      if (GTK_TOGGLE_BUTTON (widget)->active) 
1632      {
1633         /* Se il programma si &egrave; arrivato a questo punto, il bottone
1634          * a commutazione &egrave; sollevato */
1635     
1636     } else {
1637     
1638         /* il bottone &egrave; abbassato */
1639      }
1640  }
1641  </verb></tscreen>
1642
1643 <!--
1644
1645 COMMENTED!
1646
1647 <tscreen><verb>
1648 guint gtk_toggle_button_get_type (void);
1649 </verb></tscreen>
1650 <p>
1651 No idea... they all have this, but I dunno what it is :)
1652
1653
1654 <tscreen><verb>
1655 void gtk_toggle_button_set_mode (GtkToggleButton *toggle_button,
1656                                  gint draw_indicator);
1657 </verb></tscreen>
1658 <p>
1659 No idea.
1660 -->
1661
1662 <tscreen><verb>
1663 void gtk_toggle_button_set_state (GtkToggleButton *toggle_button,
1664                                   gint state);
1665 </verb></tscreen>
1666 <p>
1667 La chiamata qui sopra pu&ograve; essere usata per fare l'assegnazione dello stato
1668 del bottone a commutazione e dei suoi figli, il radio-bottone e il bottone di
1669 controllo. Passando come primo argomento a questa funzione il vostro bottone e
1670 come secondo argomento il valore TRUE o FALSE, si pu&ograve; specificare se il
1671 bottone deve essere sollevato (rilasciato) o abbassato (premuto). Il valore
1672 di difetto &egrave; sollevato, cio&egrave; FALSE.
1673
1674 Notate che quando usate la funzione  gtk_toggle_button_set_state(), e lo
1675 stato viene cambiato, si ha il risultato che il bottone emette il segnale
1676 ``clicked''.
1677
1678 <tscreen><verb>
1679 void       gtk_toggle_button_toggled (GtkToggleButton *toggle_button);
1680 </verb></tscreen>
1681 <p>
1682 Questa funzione semplicemente commuta il bottone, ed emette il segnale ``toggled''.
1683
1684 <sect1> Bottoni di Controllo (Check Buttons)
1685 <p>
1686 I bottoni di controllo ereditano molte propriet&agrave; e funzioni dal bottone a commutazione,
1687 ma hanno un aspetto un po' diverso. Invece di essere bottoni contenenti del testo,
1688 si tratta di quadratini con del testo alla propria destra. Questi bottoni sono
1689 spesso usati nelle applicazioni per commutare fra lo stato attivato e disattivato delle
1690 opzioni.
1691
1692 Le due funzioni di creazione sono analoghe a quelle del bottone normale..
1693
1694 <tscreen><verb>
1695 GtkWidget* gtk_check_button_new (void);
1696
1697 GtkWidget* gtk_check_button_new_with_label (gchar *label);
1698 </verb></tscreen>
1699
1700 La funzione new_with_label crea un bottone di controllo con una etichetta
1701 a fianco di esso.
1702
1703 Per controllare lo stato del check button si opera in modo identico al bottone
1704 a commutazione.
1705
1706 <sect1> Radio-Bottoni (Radio Buttons)
1707 <p>
1708 I radio-bottoni sono simili ai bottoni di controllo, tranne che per il
1709 fatto che sono sempre raggruppati in modo che solo uno alla volta di essi
1710 pu&ograve; essere selezionato (premuto). Tornano utili quando nella propria applicazione
1711 si ha bisogno di selezionare una opzione da una breve lista.
1712
1713 La creazione di un nuovo radio-bottone si fa con una di queste chiamate:
1714
1715 <tscreen><verb>
1716 GtkWidget* gtk_radio_button_new (GSList *group);
1717
1718 GtkWidget* gtk_radio_button_new_with_label (GSList *group,
1719                                             gchar *label);
1720 </verb></tscreen>
1721 <p>
1722 Avrete notato l'argomento in pi&ugrave; che c'&egrave; in queste chiamate. Queste hanno
1723 infatti bisogno dela specificazione di un ``gruppo'' per svolgere il loro compito.
1724 Per il primo bottone di un gruppo si deve passare come primo argomento il valore
1725 NULL. Dopodich&eacute; potete creare un gruppo usando la funzione:
1726
1727 <tscreen><verb>
1728 GSList* gtk_radio_button_group (GtkRadioButton *radio_button);
1729 </verb></tscreen>
1730
1731 <p>
1732 A questo punto potete passare questo gruppo ad ogni chiamata successiva a
1733 gtk_radio_button_new o new_with_label. E' anche una buona idea specificare
1734 esplicitamente  quale dei bottoni dovr&agrave; essere quello premuto per difetto,
1735 usando:
1736
1737 <tscreen><verb>
1738 void gtk_toggle_button_set_state (GtkToggleButton *toggle_button,
1739                                   gint state);
1740 </verb></tscreen>
1741 <p>
1742 Questa funzione &egrave; descritta nella sezione sui bottoni a commutazione, e funziona
1743 nello stesso identico modo.
1744
1745 <p>
1746 [Inserir&ograve; un esempio di come usare questi oggetti, penso che sarebbe molto
1747 utile]
1748
1749
1750 <sect> Alcuni Widget
1751 <p>
1752 <sect1> L'Etichetta (Label)
1753 <p>
1754 Le etichette sono molto usate in GTK, e sono relativamente semplici. Le
1755 etichette non emettono segnali, dal momento che non hanno una finestra
1756 X a loro assegnata. Se avete la necessit&agrave; di avere dei segnali o di fare
1757 delle operazioni di clipping, potete usare il widget EventBox.
1758
1759 Per creare una nuova etichetta, si usa:
1760
1761 <tscreen><verb>
1762 GtkWidget* gtk_label_new (char *str);
1763 </verb></tscreen>
1764
1765 In cui l'unico argomento &egrave; la stringa che si vuole sia mostrata.
1766
1767 Per cambiare il testo dell'etichetta dopo che &egrave; stata creata, si usa
1768 la funzione:
1769
1770 <tscreen><verb>
1771 void gtk_label_set (GtkLabel  *label,
1772                     char      *str);
1773 </verb></tscreen>
1774 <p>
1775 in cui il primo argomento &egrave; l'etichetta creata in precedenza (di cui si
1776 fa il cast usando la macro GTK_LABEL()), mentre il secondo &egrave; la nuova
1777 stringa.
1778
1779 Nel caso, lo spazio necessario per la nuova stringa verr&agrave; regolato automaticamente.
1780
1781 Per ottenere la stringa corrente si usa:
1782
1783 <tscreen><verb>
1784 void gtk_label_get (GtkLabel  *label,
1785                     char     **str);
1786 </verb></tscreen>
1787
1788 in cui il primo argomento &egrave; l'etichetta che avete creato, e il secondo
1789 &egrave; il valore di ritorno per la stringa.
1790
1791
1792 <sect1>Il Widget Suggerimenti (Tooltips)
1793 <p>
1794 I suggerimenti sono piccole stringhe di testo che spuntano quando lasciate il
1795 puntatore su un bottone o un altro widget per qualche secondo. Sono piuttosto
1796 semplici da usare, per cui ne dar&ograve; la spiegazione senza corredarla di esempi.
1797 Se volede vedere un po' di codice, date un'occhiata al programma testgtk.c
1798 distribuito con GTK.
1799 <p>
1800 Con alcuni widget (per esempio con l'etichetta) i suggerimenti non funzionano.
1801 <p>
1802 La prima chiamata che si usa per creare un nuovo tooltip &egrave; la seguente.
1803 In una data funzione, &egrave; necessario chiamarla una sola volta: il GtkTooltip
1804 che viene ritornato da questa funzione pu&ograve; essere usato per creare suggerimenti
1805 multipli.
1806
1807 <tscreen><verb>
1808 GtkTooltips *gtk_tooltips_new (void);
1809 </verb></tscreen>
1810
1811 Una volta creato un nuovo suggerimento e il widget su cui lo volete usare,
1812 basta usare la seguente chiamata per fare l'assegnazione:
1813
1814 <tscreen><verb>
1815 void gtk_tooltips_set_tips   (GtkTooltips *tooltips,
1816                               GtkWidget   *widget,
1817                               gchar       *tips_text);
1818 </verb></tscreen>
1819
1820 Il primo argomento &egrave; il suggerimento che era gi&agrave; stato creato, che &egrave; seguito
1821 dal widget da cui volete che spunti il suggerimento e dal testo che volete
1822 venga mostrato.
1823 <p>
1824 Ecco un piccolo esempio:
1825
1826 <tscreen><verb>
1827 GtkTooltips *tooltips;
1828 GtkWidget *button;
1829 ...
1830 tooltips = gtk_tooltips_new ();
1831 button = gtk_button_new_with_label ("button 1");
1832 ...
1833 gtk_tooltips_set_tips (tooltips, button, "This is button 1");
1834 </verb></tscreen>
1835
1836 Ci sono anche altre funzioni che si usano con i suggerimenti. Eccone una lista
1837 con una breve descrizione di quello che fanno.
1838
1839 <tscreen><verb>
1840 void gtk_tooltips_destroy    (GtkTooltips *tooltips);
1841 </verb></tscreen>
1842
1843 Distrugge un suggerimento esistente.
1844
1845 <tscreen><verb>
1846 void gtk_tooltips_enable     (GtkTooltips *tooltips);
1847 </verb></tscreen>
1848
1849 Abilita  un gruppo di suggerimenti disbilitato.
1850
1851 <tscreen><verb>
1852 void gtk_tooltips_disable    (GtkTooltips *tooltips);
1853 </verb></tscreen>
1854
1855 Disabilita un gruppo di suggerimenti abilitato.
1856
1857 <tscreen><verb>
1858 void gtk_tooltips_set_delay  (GtkTooltips *tooltips,
1859                               gint         delay);
1860
1861 </verb></tscreen>
1862 Stabilisce quanti millisecondi si deve mantenere il puntatore sopra al
1863 widget prima che venga mostrato il suggerimento. Il valore di difetto
1864 &egrave; di 1000 millisecondi.
1865
1866 <tscreen><verb>
1867 void      gtk_tooltips_set_tips (GtkTooltips *tooltips,
1868                                  GtkWidget   *widget,
1869                                  gchar    *tips_text);
1870 </verb></tscreen>
1871
1872 Cambia il testo di un suggerimento gi&agrave; esistente.
1873
1874 <tscreen><verb>
1875 void gtk_tooltips_set_colors (GtkTooltips *tooltips,
1876                               GdkColor    *background,
1877                               GdkColor    *foreground);
1878 </verb></tscreen>
1879
1880 Assegna i colori di primo piano e di sfondo dei suggerimenti. (Non ho idea
1881 di come si specifichino i colori).
1882 <p>
1883 E questo &egrave; tutto riguardo alle funzioni relative ai suggerimenti. Pi&ugrave;
1884 di quanto avreste mai voluto sapere :)
1885
1886 <sect1> La Barra di Avanzamento (Progress Bar)
1887 <p>
1888 Le barre di avanzamento sono usate per mostrare lo stato di una operazione. Come potete
1889 vedere nel frammento di codice qui sotto, sono piuttosto semplici da usare.
1890 Ma prima vediamo come cominciare con la chiamata per creare una nuova progrss
1891 bar.
1892
1893 <tscreen><verb>
1894 GtkWidget *gtk_progress_bar_new (void);
1895 </verb></tscreen>
1896
1897 Ora che la barra di avanzamento &egrave; stata creata, possiamo usarla..
1898
1899 <tscreen><verb>
1900 void gtk_progress_bar_update (GtkProgressBar *pbar, gfloat percentage);
1901 </verb></tscreen>
1902
1903 Il primo argomento &egrave; la barra di avanzamento su cui volete lavorare, e il secondo
1904 &egrave; la quantit&agrave; 'completato', cio&egrave; la quantit&agrave; di riempimento della progress
1905 bar fra 0 e 100% (un numero reale fra 0 e 1).
1906
1907 Le barre di avanzamento sono usate di solito con funzioni di timeout o altre di
1908 questo tipo (vedi alla sezione <ref id="sec_timeouts" name="Timeouts,
1909 I/O and Idle Functions">) per dare l'illusione del multitasking. Tutte
1910 usano la funzione gtk_progress_bar_update nello stesso modo.
1911
1912 Ecco un esempio di barra di avanzamento, in cui l'aggiornamento avviene usando
1913 dei timeout. Questo codice vi mostra anche come riinizializzare le
1914 barre di avanzamento.
1915
1916 <tscreen><verb>
1917 #include <gtk/gtk.h>
1918
1919 static int ptimer = 0;
1920 int pstat = TRUE;
1921
1922 /* Questa funzione incrementa e aggiorna la barra di avanzamento, e la rimette
1923    a zero se pstat &egrave; FALSE */
1924 gint progress (gpointer data)
1925 {
1926     gfloat pvalue;
1927     
1928     /* ottiene il valore corrente della status bar */
1929     pvalue = GTK_PROGRESS_BAR (data)->percentage;
1930     
1931     if ((pvalue >= 1.0) || (pstat == FALSE)) {
1932         pvalue = 0.0;
1933         pstat = TRUE;
1934     }
1935     pvalue += 0.01;
1936     
1937     gtk_progress_bar_update (GTK_PROGRESS_BAR (data), pvalue);
1938     
1939     return TRUE;
1940 }
1941
1942 /* Questa funzione segnala la riinizializzazione della 
1943    barra di avanzamento */
1944 void progress_r (void)
1945 {  
1946     pstat = FALSE;  
1947 }
1948
1949 void destroy (GtkWidget *widget, gpointer *data)
1950 {
1951     gtk_main_quit ();
1952 }
1953
1954 int main (int argc, char *argv[])
1955 {
1956     GtkWidget *window;
1957     GtkWidget *button;
1958     GtkWidget *label;
1959     GtkWidget *table;
1960     GtkWidget *pbar;
1961     
1962     gtk_init (&amp;argc, &amp;argv);
1963     
1964     window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1965     
1966     gtk_signal_connect (GTK_OBJECT (window), "delete_event",
1967                         GTK_SIGNAL_FUNC (destroy), NULL);
1968     
1969     gtk_container_border_width (GTK_CONTAINER (window), 10);
1970     
1971     table = gtk_table_new(3,2,TRUE);
1972     gtk_container_add (GTK_CONTAINER (window), table);
1973     
1974     label = gtk_label_new ("Progress Bar Example");
1975     gtk_table_attach_defaults(GTK_TABLE(table), label, 0,2,0,1);
1976     gtk_widget_show(label);
1977     /* Crea una nuova barra di avanzamento, impacchettala nella tabella
1978        e mostrala */
1979     pbar = gtk_progress_bar_new ();
1980     gtk_table_attach_defaults(GTK_TABLE(table), pbar, 0,2,1,2);
1981     gtk_widget_show (pbar);
1982     
1983     /* Attiva un timeout che gestisca l'aggiornamento automatico della barra */
1984     ptimer = gtk_timeout_add (100, progress, pbar);
1985     
1986     /* Questo bottone segnala alla barra che deve essere resettata */
1987     button = gtk_button_new_with_label ("Reset");
1988     gtk_signal_connect (GTK_OBJECT (button), "clicked",
1989                         GTK_SIGNAL_FUNC (progress_r), NULL);
1990     gtk_table_attach_defaults(GTK_TABLE(table), button, 0,1,2,3);
1991     gtk_widget_show(button);
1992     
1993     button = gtk_button_new_with_label ("Cancel");
1994     gtk_signal_connect (GTK_OBJECT (button), "clicked",
1995                         GTK_SIGNAL_FUNC (destroy), NULL);
1996     
1997     gtk_table_attach_defaults(GTK_TABLE(table), button, 1,2,2,3);
1998     gtk_widget_show (button);
1999     
2000     gtk_widget_show(table);
2001     gtk_widget_show(window);
2002     
2003     gtk_main ();
2004     
2005     return 0;
2006 }
2007 </verb></tscreen>
2008
2009 In questo programmino ci sono quattro aree che riguardano il modo di
2010 uso generale delle Barre di Avanzamento; le vediamo ora nell'ordine.
2011
2012 <tscreen><verb>
2013 pbar = gtk_progress_bar_new ();
2014 </verb></tscreen>
2015
2016 Questo codice crea una nuova barra ciamata pbar.
2017
2018 <tscreen><verb>
2019 ptimer = gtk_timeout_add (100, progress, pbar);
2020 </verb></tscreen>
2021
2022 Questo codice usa dei timeout per abilitare degli intervalli di tempo uguali.
2023 Per usare le barre di avanzamento non &egrave; per&ograve; necessario servirsi di timeout.
2024
2025 <tscreen><verb>
2026 pvalue = GTK_PROGRESS_BAR (data)->percentage;
2027 </verb></tscreen>
2028
2029 Qui si assegna a pvalue il valore corrente della percentuale di avanzamento.
2030
2031 <tscreen><verb>
2032 gtk_progress_bar_update (GTK_PROGRESS_BAR (data), pvalue);
2033 </verb></tscreen>
2034
2035 Infine, questo codice aggiorna la barra di avanzamento con il valore di pvalue.
2036
2037 Questo &egrave; tutto quanto c'&egrave; da sapere sulle barre di avanzamento, divertitevi.
2038
2039 <sect1> Dialoghi
2040 <p>
2041
2042 Il widget ``Dialogo'' &egrave; molto semplice: si tratta in realt&agrave; di una finestra
2043 con alcuni elementi pre-impacchettati. La struttura di un dialogo &egrave; la
2044 seguente:
2045
2046 <tscreen><verb>
2047 struct GtkDialog
2048 {
2049       GtkWindow window;
2050     
2051       GtkWidget *vbox;
2052       GtkWidget *action_area;
2053 };
2054 </verb></tscreen>
2055
2056 Come potete vedere, crea semplicemente una finestra vi inserisce una vbox
2057 in cima, poi un separatore e infine una hbox come ``area di azione''.
2058
2059 Un Dialogo pu&ograve; essere utilizzato per messaggi per l'utente e
2060 altri scopi simili. E' un widget molto essenziale, che ha una sola funzione,
2061 e precisamente:
2062
2063 <tscreen><verb>
2064 GtkWidget* gtk_dialog_new (void);
2065 </verb></tscreen>
2066
2067 Per cui, per creare una nuova finestra di dialogo, uate:
2068
2069 <tscreen><verb>
2070 GtkWidget window;
2071 window = gtk_dialog_new ();
2072 </verb></tscreen>
2073
2074 Questa funzione crea una finestra di dialogo, dopodich&eacute; sta a voi 
2075 utilizzarla. Potete mettere un bottone nella action_area facendo
2076 qualcosa del tipo:
2077
2078 <tscreen><verb>
2079 button = ...
2080 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area), button,
2081                     TRUE, TRUE, 0);
2082 gtk_widget_show (button);
2083 </verb></tscreen>
2084
2085 Potreste anche aggiungere, ad esempio, un'etichetta all'area della vbox,
2086 con qualcosa di questo genere:
2087
2088 <tscreen><verb>
2089 label = gtk_label_new ("Dialogs are groovy");
2090 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox), label, TRUE,
2091                     TRUE, 0);
2092 gtk_widget_show (label);
2093 </verb></tscreen>
2094
2095 Per provare a usare una finestra di dialogo, potreste provare a mettere
2096 due bottoni nella action_area, per esempio un bottone ``Cancella'' ed un
2097 bottone ``OK'' e un'etichetta nella vbox che chieda qualcosa all'utente o
2098 segnali un errore. Poi potreste collegare un diverso segnale a ciascun
2099 bottone ed eseguire l'operazione che l'utente che viene scelta dall'utente.
2100
2101
2102 <sect1> Pixmaps
2103 <p>
2104
2105 Le Pixmap sono strutture dati che contengono immagini. Queste immagini
2106 possono poi essere utilizzate in varie occasioni, per esempio come 
2107 icone sul desktop X-Window o come cusori. Una bitmap &egrave; una pixmap a due
2108 colori.
2109
2110 Per usare una pixmap in GTK, dobbiamo in primo luogo creare una struttura
2111 GdkPixmap utilizzando le routine disponibili nello strato GDK. Una Pixmap
2112 pu&ograve; essere creata a partire da dati presenti in memoria o letti da un file.
2113 Vedremo ora una ad una le chiamate utilizzate per creare una pixmap.
2114
2115 <tscreen><verb>
2116 GdkPixmap *gdk_bitmap_create_from_data( GdkWindow *window,
2117                                         gchar     *data,
2118                                         gint      width,
2119                                         gint      height );
2120 </verb></tscreen>
2121 <p>
2122 Si usa questa routine per creare una pixmap ad un solo piano (2 colori) da
2123 dati disponibili in memoria. Ogni bit nei dati indica lo stato acceso o
2124 spento di un pixel. L'altezza (height) e la larghezza (width) sono espresse
2125  in pixel. GdkWindow &egrave; un puntatore alla finestra corrente, dal momento che
2126 le risorse di una pixmap hanno significato solo nel contesto dello schermo 
2127 in cui deve essere mostrata.
2128
2129 <tscreen><verb>
2130 GdkPixmap* gdk_pixmap_create_from_data( GdkWindow  *window,
2131                                         gchar      *data,
2132                                         gint        width,
2133                                         gint        height,
2134                                         gint        depth,
2135                                         GdkColor   *fg,
2136                                         GdkColor   *bg );
2137 </verb></tscreen>
2138
2139 Questa &egrave; usata per creare una pixmap con la profondit&agrave; data (depth, ossia 
2140 numero di colori) usando i dati specificati. fg e bg indicano i colori da
2141 usare per il primo piano e per lo sfondo.
2142
2143 <tscreen><verb>
2144 GdkPixmap* gdk_pixmap_create_from_xpm( GdkWindow  *window,
2145                                        GdkBitmap **mask,
2146                                        GdkColor   *transparent_color,
2147                                        const gchar *filename );
2148 </verb></tscreen>
2149
2150 Il formato XPM &egrave; una rappresentazione di pixmap leggibile per X Window. E' una
2151 rappresentazione molto diffusa, e sono disponibili parecchi programmi per creare
2152 immagini in questo formato. Il file specificato da ``filename'' deve contenere
2153 un'immagine in questo formato, che viene caricato nella struttura pixmap.
2154 La maschera (mask) specifica quali pixel della pixmap devono essere opachi.
2155 Tutti gli altri pixel sono colorati usando il colore specificato da
2156 transparent_color. Pi&ugrave; sotto mostreremo un esempio di uso di questa funzione.
2157
2158 <tscreen><verb>
2159 GdkPixmap* gdk_pixmap_create_from_xpm_d (GdkWindow  *window,
2160                                          GdkBitmap **mask,
2161                                          GdkColor   *transparent_color,
2162                                          gchar     **data);
2163 </verb></tscreen>
2164
2165 Si possono incorporare piccole immagini all'interno di un programma sotto
2166 forma di dati in formato XPM. In questo modo, invece di leggerli da un file,
2167 si possono usare questi dati per creare una pixmap. Un esempio di questo tipo
2168 di dati &egrave;
2169
2170 <tscreen><verb>
2171 /* XPM */
2172 static const char * xpm_data[] = {
2173 "16 16 3 1",
2174 "       c None",
2175 ".      c #000000000000",
2176 "X      c #FFFFFFFFFFFF",
2177 "                ",
2178 "   ......       ",
2179 "   .XXX.X.      ",
2180 "   .XXX.XX.     ",
2181 "   .XXX.XXX.    ",
2182 "   .XXX.....    ",
2183 "   .XXXXXXX.    ",
2184 "   .XXXXXXX.    ",
2185 "   .XXXXXXX.    ",
2186 "   .XXXXXXX.    ",
2187 "   .XXXXXXX.    ",
2188 "   .XXXXXXX.    ",
2189 "   .XXXXXXX.    ",
2190 "   .........    ",
2191 "                ",
2192 "                "};
2193 </verb></tscreen>
2194
2195 <tscreen><verb>
2196 void gdk_pixmap_destroy( GdkPixmap  *pixmap );
2197 </verb></tscreen>
2198 <p>
2199 Quando abbiamo finito di usare una pixmap e pensiamo di non doverla riutilizzare
2200 presto, &egrave; una buona idea liberare queste risorse usando la funzione 
2201 dk_pixmap_destroy. Le pixmap devono essere considerate una risorsa preziosa.
2202
2203 Quando abbiamo creato una pixmap, possiamo mostrarla come un widget GTK.
2204 E' necessario creare un widget pixmap che contenga una pixmap GDK. Questa
2205 operazione viene compiuta usando
2206
2207 <tscreen><verb>
2208 GtkWidget* gtk_pixmap_new( GdkPixmap  *pixmap,
2209                            GdkBitmap  *mask );
2210 </verb></tscreen>
2211 <p>
2212 Le altre chiamate per i widget pixmap sono
2213
2214 <tscreen><verb>
2215 guint gtk_pixmap_get_type( void );
2216 void  gtk_pixmap_set( GtkPixmap  *pixmap,
2217                       GdkPixmap  *val,
2218                       GdkBitmap  *mask);
2219 void  gtk_pixmap_get( GtkPixmap  *pixmap,
2220                       GdkPixmap **val,
2221                       GdkBitmap **mask);
2222 </verb></tscreen>
2223 <p>
2224 La funzione gtk_pixmap_set viene usata per cambiare la pixmap che viene
2225 gestita correntemente dal widget.
2226 gtk_pixmap_set is used to change the pixmap that the widget is currently
2227 managing.  ``val'' &egrave; la pixmap che &egrave; stata creata usando il GDK.
2228 Segue un esempio di uso di una pixmap in un bottone.
2229
2230 <tscreen><verb>
2231
2232 #include <gtk/gtk.h>
2233
2234
2235 /* dat XPM dell'icona Apri File */
2236 static const char * xpm_data[] = {
2237 "16 16 3 1",
2238 "       c None",
2239 ".      c #000000000000",
2240 "X      c #FFFFFFFFFFFF",
2241 "                ",
2242 "   ......       ",
2243 "   .XXX.X.      ",
2244 "   .XXX.XX.     ",
2245 "   .XXX.XXX.    ",
2246 "   .XXX.....    ",
2247 "   .XXXXXXX.    ",
2248 "   .XXXXXXX.    ",
2249 "   .XXXXXXX.    ",
2250 "   .XXXXXXX.    ",
2251 "   .XXXXXXX.    ",
2252 "   .XXXXXXX.    ",
2253 "   .XXXXXXX.    ",
2254 "   .........    ",
2255 "                ",
2256 "                "};
2257
2258
2259 /* quando invocata (con il segnale delete_event), termina l'applicazione. */
2260 void close_application( GtkWidget *widget, gpointer *data ) {
2261     gtk_main_quit();
2262 }
2263
2264
2265 /* invocata se il bottone &egrave; clickato. Stampa semplicemente un messaggio */
2266 void button_clicked( GtkWidget *widget, gpointer *data ) {
2267     printf( "button clicked\n" );
2268 }
2269
2270
2271
2272
2273 int main( int argc, char *argv[] )
2274 {
2275     /* i widget sono memorizzati nel tipo GtkWidget */
2276     GtkWidget *window, *pixmapwid, *button;
2277     GdkPixmap *pixmap;
2278     GdkBitmap *mask;
2279     GtkStyle *style;
2280     
2281     /* crea la finestra principale, e collega il segnale delete_event
2282        alla terminazione dell'applicazione */
2283     gtk_init( &amp;argc, &amp;argv );
2284     window = gtk_window_new( GTK_WINDOW_TOPLEVEL );
2285     gtk_signal_connect( GTK_OBJECT (window), "delete_event",
2286                         GTK_SIGNAL_FUNC (close_application), NULL );
2287     gtk_container_border_width( GTK_CONTAINER (window), 10 );
2288     gtk_widget_show( window );
2289
2290     /* la pixmap proviene da gdk */
2291     style = gtk_widget_get_style( window );
2292     pixmap = gdk_pixmap_create_from_xpm_d( window->window,  &amp;mask,
2293                                            &amp;style->bg[GTK_STATE_NORMAL],
2294                                            (gchar **)xpm_data );
2295
2296     /* un widget pixmap per contenere la pixmap */
2297     pixmapwid = gtk_pixmap_new( pixmap, mask );
2298     gtk_widget_show( pixmapwid );
2299
2300     /* un bottone per contenere il widget pixmap */
2301     button = gtk_button_new();
2302     gtk_container_add( GTK_CONTAINER(button), pixmapwid );
2303     gtk_container_add( GTK_CONTAINER(window), button );
2304     gtk_widget_show( button );
2305
2306     gtk_signal_connect( GTK_OBJECT(button), "clicked",
2307                         GTK_SIGNAL_FUNC(button_clicked), NULL );
2308
2309     /* mostra la finestra */
2310     gtk_main ();
2311           
2312     return 0;
2313 }
2314 </verb></tscreen>
2315
2316
2317 Per caricare una pixmap da un file XPM chiamato icon0.xpm che si trova
2318 nella direttorio corrente, avremmo creato la pixmap in questo modo:
2319
2320 <tscreen><verb>
2321     /* carica una pixmap da un file */
2322     pixmap = gdk_pixmap_create_from_xpm( window->window, &amp;mask,
2323                                          &amp;style->bg[GTK_STATE_NORMAL],
2324                                          "./icon0.xpm" );
2325     pixmapwid = gtk_pixmap_new( pixmap, mask );
2326     gtk_widget_show( pixmapwid );
2327     gtk_container_add( GTK_CONTAINER(window), pixmapwid );
2328 </verb></tscreen>
2329
2330
2331 Usare le Sagome
2332 <p>
2333 Uno degli svantaggi di usare le pixmap &egrave; costituito dal fatto che l'oggetto
2334 mostrato &egrave; sempre rettangolare, a prescindere dall'immagine. Ci piacerebbe
2335 invece poter crare dei desktop e delle immagini con forme pi&ugrave; naturali. Per
2336 esempio, per l'interfaccia di un gioco, potremmo volere avere dei pulsanti
2337 circolari. Il modo per ottenere questo effetto &egrave; di usare delle finestre
2338 sagomate.
2339
2340 Una finestra sagomata &egrave; semplicemente una pixmap in cui i pixel dello
2341 sfondo sono trasparenti. In questo modo, se l'immagine di sfondo &egrave; 
2342 multicolore, possiamo evitare di sovrascriverla con un bordo rettangolare
2343 attorno all'icona. Il prossimo esempio mostra una carriola sul desktop.
2344
2345 <tscreen><verb>
2346
2347 #include <gtk/gtk.h>
2348
2349
2350
2351 /* XPM */
2352 static char * WheelbarrowFull_xpm[] = {
2353 "48 48 64 1",
2354 "       c None",
2355 ".      c #DF7DCF3CC71B",
2356 "X      c #965875D669A6",
2357 "o      c #71C671C671C6",
2358 "O      c #A699A289A699",
2359 "+      c #965892489658",
2360 "@      c #8E38410330C2",
2361 "#      c #D75C7DF769A6",
2362 "$      c #F7DECF3CC71B",
2363 "%      c #96588A288E38",
2364 "&amp;      c #A69992489E79",
2365 "*      c #8E3886178E38",
2366 "=      c #104008200820",
2367 "-      c #596510401040",
2368 ";      c #C71B30C230C2",
2369 ":      c #C71B9A699658",
2370 ">      c #618561856185",
2371 ",      c #20811C712081",
2372 "<      c #104000000000",
2373 "1      c #861720812081",
2374 "2      c #DF7D4D344103",
2375 "3      c #79E769A671C6",
2376 "4      c #861782078617",
2377 "5      c #41033CF34103",
2378 "6      c #000000000000",
2379 "7      c #49241C711040",
2380 "8      c #492445144924",
2381 "9      c #082008200820",
2382 "0      c #69A618611861",
2383 "q      c #B6DA71C65144",
2384 "w      c #410330C238E3",
2385 "e      c #CF3CBAEAB6DA",
2386 "r      c #71C6451430C2",
2387 "t      c #EFBEDB6CD75C",
2388 "y      c #28A208200820",
2389 "u      c #186110401040",
2390 "i      c #596528A21861",
2391 "p      c #71C661855965",
2392 "a      c #A69996589658",
2393 "s      c #30C228A230C2",
2394 "d      c #BEFBA289AEBA",
2395 "f      c #596545145144",
2396 "g      c #30C230C230C2",
2397 "h      c #8E3882078617",
2398 "j      c #208118612081",
2399 "k      c #38E30C300820",
2400 "l      c #30C2208128A2",
2401 "z      c #38E328A238E3",
2402 "x      c #514438E34924",
2403 "c      c #618555555965",
2404 "v      c #30C2208130C2",
2405 "b      c #38E328A230C2",
2406 "n      c #28A228A228A2",
2407 "m      c #41032CB228A2",
2408 "M      c #104010401040",
2409 "N      c #492438E34103",
2410 "B      c #28A2208128A2",
2411 "V      c #A699596538E3",
2412 "C      c #30C21C711040",
2413 "Z      c #30C218611040",
2414 "A      c #965865955965",
2415 "S      c #618534D32081",
2416 "D      c #38E31C711040",
2417 "F      c #082000000820",
2418 "                                                ",
2419 "          .XoO                                  ",
2420 "         +@#$%o&amp;                                ",
2421 "         *=-;#::o+                              ",
2422 "           >,<12#:34                            ",
2423 "             45671#:X3                          ",
2424 "               +89<02qwo                        ",
2425 "e*                >,67;ro                       ",
2426 "ty>                 459@>+&amp;&amp;                    ",
2427 "$2u+                  ><ipas8*                  ",
2428 "%$;=*                *3:.Xa.dfg>                ",
2429 "Oh$;ya             *3d.a8j,Xe.d3g8+             ",
2430 " Oh$;ka          *3d$a8lz,,xxc:.e3g54           ",
2431 "  Oh$;kO       *pd$%svbzz,sxxxxfX..&amp;wn>         ",
2432 "   Oh$@mO    *3dthwlsslszjzxxxxxxx3:td8M4       ",
2433 "    Oh$@g&amp; *3d$XNlvvvlllm,mNwxxxxxxxfa.:,B*     ",
2434 "     Oh$@,Od.czlllllzlmmqV@V#V@fxxxxxxxf:%j5&amp;   ",
2435 "      Oh$1hd5lllslllCCZrV#r#:#2AxxxxxxxxxcdwM*  ",
2436 "       OXq6c.%8vvvllZZiqqApA:mq:Xxcpcxxxxxfdc9* ",
2437 "        2r<6gde3bllZZrVi7S@SV77A::qApxxxxxxfdcM ",
2438 "        :,q-6MN.dfmZZrrSS:#riirDSAX@Af5xxxxxfevo",
2439 "         +A26jguXtAZZZC7iDiCCrVVii7Cmmmxxxxxx%3g",
2440 "          *#16jszN..3DZZZZrCVSA2rZrV7Dmmwxxxx&amp;en",
2441 "           p2yFvzssXe:fCZZCiiD7iiZDiDSSZwwxx8e*>",
2442 "           OA1<jzxwwc:$d%NDZZZZCCCZCCZZCmxxfd.B ",
2443 "            3206Bwxxszx%et.eaAp77m77mmmf3&amp;eeeg* ",
2444 "             @26MvzxNzvlbwfpdettttttttttt.c,n&amp;  ",
2445 "             *;16=lsNwwNwgsvslbwwvccc3pcfu<o    ",
2446 "              p;<69BvwwsszslllbBlllllllu<5+     ",
2447 "              OS0y6FBlvvvzvzss,u=Blllj=54       ",
2448 "               c1-699Blvlllllu7k96MMMg4         ",
2449 "               *10y8n6FjvllllB<166668           ",
2450 "                S-kg+>666<M<996-y6n<8*          ",
2451 "                p71=4 m69996kD8Z-66698&amp;&amp;        ",
2452 "                &amp;i0ycm6n4 ogk17,0<6666g         ",
2453 "                 N-k-<>     >=01-kuu666>        ",
2454 "                 ,6ky&amp;      &amp;46-10ul,66,        ",
2455 "                 Ou0<>       o66y<ulw<66&amp;       ",
2456 "                  *kk5       >66By7=xu664       ",
2457 "                   <<M4      466lj<Mxu66o       ",
2458 "                   *>>       +66uv,zN666*       ",
2459 "                              566,xxj669        ",
2460 "                              4666FF666>        ",
2461 "                               >966666M         ",
2462 "                                oM6668+         ",
2463 "                                  *4            ",
2464 "                                                ",
2465 "                                                "};
2466
2467
2468 /* quando invocata (con il segnale delete_event), termina l'applicazione. */
2469 void close_application( GtkWidget *widget, gpointer *data ) {
2470     gtk_main_quit();
2471 }
2472
2473
2474 int main (int argc, char *argv[])
2475 {
2476     /* il tipo di dato per i widget &egrave; GtkWidget */
2477     GtkWidget *window, *pixmap, *fixed;
2478     GdkPixmap *gdk_pixmap;
2479     GdkBitmap *mask;
2480     GtkStyle *style;
2481     GdkGC *gc;
2482     
2483     /* crea la finestra principale e collega il segnale delete_event per
2484        terminare l'applicazione. Notare che non mettiamo un titolo 
2485        alla finestra. */
2486     gtk_init (&amp;argc, &amp;argv);
2487     window = gtk_window_new( GTK_WINDOW_POPUP );
2488     gtk_signal_connect (GTK_OBJECT (window), "delete_event",
2489                         GTK_SIGNAL_FUNC (close_application), NULL);
2490     gtk_widget_show (window);
2491
2492     /* ora occupiamoci della pixmap e del widget pixmap */
2493     style = gtk_widget_get_default_style();
2494     gc = style->black_gc;
2495     gdk_pixmap = gdk_pixmap_create_from_xpm_d( window->window, &amp;mask,
2496                                              &amp;style->bg[GTK_STATE_NORMAL],
2497                                              WheelbarrowFull_xpm );
2498     pixmap = gtk_pixmap_new( gdk_pixmap, mask );
2499     gtk_widget_show( pixmap );
2500
2501     /* Per mostrare la pixmap, usiamo un widget "fixed" in cui metterla */
2502     fixed = gtk_fixed_new();
2503     gtk_widget_set_usize( fixed, 200, 200 );
2504     gtk_fixed_put( GTK_FIXED(fixed), pixmap, 0, 0 );
2505     gtk_container_add( GTK_CONTAINER(window), fixed );
2506     gtk_widget_show( fixed );
2507
2508     /* Questa maschera tutto tranne l'immagine stessa */
2509     gtk_widget_shape_combine_mask( window, mask, 0, 0 );
2510     
2511     /* mostra la finestra */
2512     gtk_widget_set_uposition( window, 20, 400 );
2513     gtk_widget_show( window );
2514     gtk_main ();
2515           
2516     return 0;
2517 }
2518 </verb></tscreen>
2519 <p>
2520 Per rendere sensibile l'immagine della carriola, potremmo collegare
2521 il segnale di pressione del bottone in modo che venga compiuta una certa
2522 azione. Le prossime linee renderebbero l'immagine sensibile alla pressione
2523 di un bottone del mouse che fa s&igrave; che l'applicazione termini.
2524
2525 <tscreen><verb>
2526 gtk_widget_set_events( window,
2527                        gtk_widget_get_events( window ) |
2528                        GDK_BUTTON_PRESS_MASK );
2529
2530 gtk_signal_connect( GTK_OBJECT(window), "button_press_event",
2531                     GTK_SIGNAL_FUNC(close_application), NULL );
2532 </verb></tscreen>
2533
2534
2535 <sect> Widget Contenitore
2536
2537 <sect1> Il widget Blocco Note (Notebook)
2538 <p>
2539 Il widget Blocco note &egrave; un insieme di pagine sovrapposte l'una con l'altra, 
2540 ognuna contente cose diverse. Questo widget &egrave; diventato molto comune nella
2541 programmazione delle interfacce utente ed &egrave; un buon metodo per mostrare informazioni
2542 tra loro correlate ma che debbano essere mostrate separatamente.
2543
2544 <p>
2545 La prima funzione da invocare che si deve conoscere, come si pu&ograve; intuire, &egrave; usata
2546 per creare un nuovo Blocco Note.
2547
2548 <tscreen><verb>
2549 GtkWidget* gtk_notebook_new (void);
2550 </verb></tscreen>
2551
2552 Una volta che il notebook &egrave; sato creato, ci sono 12 funzioni che possono
2553 operare sul widget notebook. Guardiamole individualmente.
2554
2555 La prima che vediamo riguarda come posizionare l'indicatore di pagina.
2556 Questi inidicatori di pagina o ``linguette'' (come possono anche essere chiamati)
2557 possono essere posizionati in quattro posti: alto, basso, sinistra.destra.
2558
2559 <tscreen><verb>
2560 void gtk_notebook_set_tab_pos (GtkNotebook *notebook, GtkPositionType pos);
2561 </verb></tscreen>
2562
2563 GtkPositionType sar&agrave; uno dei seguenti valori (molto autoesplicativi)
2564 <itemize>
2565 <item> GTK_POS_LEFT
2566 <item> GTK_POS_RIGHT
2567 <item> GTK_POS_TOP
2568 <item> GTK_POS_BOTTOM
2569 </itemize>
2570
2571 GTK_POS_TOP e' il valore predefinito.
2572
2573 Ora vediamo come aggiugere le pagine al Blocco Note. Ci sono 3 modi per farlo. Diamo
2574 un'occhiata ai primi due insieme, viste che sono molto simili.
2575
2576 <tscreen><verb>
2577 void gtk_notebook_append_page (GtkNotebook *notebook, GtkWidget *child, GtkWidget *tab_label);
2578
2579 void gtk_notebook_prepend_page (GtkNotebook *notebook, GtkWidget *child, GtkWidget *tab_label);
2580 </verb></tscreen>
2581
2582 Queste funzioni aggiungono pagine al notebook inserendole rispettivamente alla fine
2583 (append) o all'inizio (prepend). *child &egrave; il widget che &egrave; posto nella pagina del
2584 notebook e *tab_label e la intestazione della pagina stessa.
2585
2586 L'ultima funzione per aggiungere una pagina al notebook contiene tutte le propriet&agrave;
2587 delle precedenti due, ma permette di specificare dove posizionare la pagina che
2588 si vuole inserire.
2589
2590 <tscreen><verb>
2591 void gtk_notebook_insert_page (GtkNotebook *notebook, GtkWidget *child, GtkWidget *tab_label, gint position);
2592 </verb></tscreen>
2593
2594 I parametri sono gli stessi di _append_ e _prepend_ tranne che per il parametro in
2595 pi&ugrave;: ``position''. 
2596 Questo parametro viene usato per specificare in che posizione ineserire la pagina.
2597
2598 Ora che conosciamo come aggiungere le pagine, vediamo come poter toglierne una.
2599
2600 <tscreen><verb>
2601 void gtk_notebook_remove_page (GtkNotebook *notebook, gint page_num);
2602 </verb></tscreen>
2603
2604 Questa funzione prende il numero della pagina specificata dal campo page_num e
2605 rimuove la pagina corrispondente dal Blocco Note.
2606
2607 Per trovare qual'&egrave; la pagina corrente nel notebook bisogna usare la funzione:
2608
2609 <tscreen><verb>
2610 gint gtk_notebook_current_page (GtkNotebook *notebook);
2611 </verb></tscreen>
2612
2613 Le prossime due funzioni sono semplicemente delle chiamate che muovono la pagina del 
2614 notebook avanti o indietro. Semplicemente forniscono le chiamate alle rispettive
2615 funzioni del widget notebook su si pu&ograve; operare. NB: quando un notebook &egrave;
2616 correntemente sull'ultima pagina e viene invocata la funzione gtk_notebook_next_page,
2617 il notebook ritorner&agrave; automaticamente alla prima pagina. Logicamente succede anche
2618 il contrario quando invochi gtk_notebook_prev_page e ti trovi sulla prima pagina.
2619
2620 <tscreen><verb>
2621 void gtk_notebook_next_page (GtkNoteBook *notebook);
2622 void gtk_notebook_prev_page (GtkNoteBook *notebook);
2623 </verb></tscreen>
2624
2625 La prossima funzione stabilisce la pagina ``attiva''. Se si vuole che la pagina
2626 principale del notebook sia per esempio la 5 (ad esempio) si pu&ograve; usare questa
2627 funzione.
2628 Se non si usa questa funzione la pagina principale sar&agrave; la 1.
2629
2630 <tscreen><verb>
2631 void gtk_notebook_set_page (GtkNotebook *notebook, gint page_num);
2632 </verb></tscreen>
2633
2634 Le prossime due funzioni aggiungono o rimuovono, rispettivamente, le intestazioni e
2635 i bordi delle pagine.
2636
2637 <tscreen><verb>
2638 void gtk_notebook_set_show_tabs (GtkNotebook *notebook, gint show_tabs);
2639 void gtk_notebook_set_show_border (GtkNotebook *notebook, gint show_border);
2640 </verb></tscreen>
2641
2642 show_tabs e show_border posso avere come valore TRUE o FALSE (0 or 1).
2643
2644 Diamo ora una occhiata ad un esempio. Si tratta di una espansione del codice preso
2645 dal file testgtk.c che &egrave; compreso in tutte le distribuzioni, e mostra 
2646 tutte le 13 funzioni. Questo piccolo programma crea una finestra con un notebook
2647 e 6 bottoni. Il notebook contiene 11 pagine, aggiunte nei 3 modi differenti (alla
2648 fine, all'inizio o in qualsiasi posizione). I bottoni permettono di girare le 
2649 intestazioni, aggiungere/rimuovere le intestazioni e i bordi, rimuovere una 
2650 pagina, cambiare la pagina avanti e indietro e uscire dal programma.
2651
2652 <tscreen><verb>
2653
2654 #include <gtk/gtk.h>
2655
2656 /* Queta funzione ruota le posizione delle linguette delle pagine */
2657 void rotate_book (GtkButton *button, GtkNotebook *notebook)
2658 {
2659     gtk_notebook_set_tab_pos (notebook, (notebook->tab_pos +1) %4);
2660 }
2661
2662 /* Aggiunge e rimuove le linguette e i bordi */
2663 void tabsborder_book (GtkButton *button, GtkNotebook *notebook)
2664 {
2665     gint tval = FALSE;
2666     gint bval = FALSE;
2667     if (notebook->show_tabs == 0)
2668             tval = TRUE; 
2669     if (notebook->show_border == 0)
2670             bval = TRUE;
2671     
2672     gtk_notebook_set_show_tabs (notebook, tval);
2673     gtk_notebook_set_show_border (notebook, bval);
2674 }
2675
2676 /* Rimuove una pagina */
2677 void remove_book (GtkButton *button, GtkNotebook *notebook)
2678 {
2679     gint page;
2680     
2681     page = gtk_notebook_current_page(notebook);
2682     gtk_notebook_remove_page (notebook, page);
2683     /* E' necessario fare un refresh del widget --
2684        Questo forza il widget a ridisegnarsi. */
2685     gtk_widget_draw(GTK_WIDGET(notebook), NULL);
2686 }
2687
2688 void delete (GtkWidget *widget, gpointer *data)
2689 {
2690     gtk_main_quit ();
2691 }
2692
2693 int main (int argc, char *argv[])
2694 {
2695     GtkWidget *window;
2696     GtkWidget *button;
2697     GtkWidget *table;
2698     GtkWidget *notebook;
2699     GtkWidget *frame;
2700     GtkWidget *label;
2701     GtkWidget *checkbutton;
2702     int i;
2703     char bufferf[32];
2704     char bufferl[32];
2705     
2706     gtk_init (&amp;argc, &amp;argv);
2707     
2708     window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2709     
2710     gtk_signal_connect (GTK_OBJECT (window), "destroy",
2711                         GTK_SIGNAL_FUNC (destroy), NULL);
2712     
2713     gtk_container_border_width (GTK_CONTAINER (window), 10);
2714     
2715     table = gtk_table_new(2,6,TRUE);
2716     gtk_container_add (GTK_CONTAINER (window), table);
2717     
2718     /* Crea un nuovo notebook, e tabilisce la posizione delle linguette */
2719     notebook = gtk_notebook_new ();
2720     gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), GTK_POS_TOP);
2721     gtk_table_attach_defaults(GTK_TABLE(table), notebook, 0,6,0,1);
2722     gtk_widget_show(notebook);
2723     
2724     /* appende una parte delle pagine */
2725     for (i=0; i < 5; i++) {
2726         sprintf(bufferf, "Append Frame %d", i+1);
2727         sprintf(bufferl, "Page %d", i+1);
2728         
2729         frame = gtk_frame_new (bufferf);
2730         gtk_container_border_width (GTK_CONTAINER (frame), 10);
2731         gtk_widget_set_usize (frame, 100, 75);
2732         gtk_widget_show (frame);
2733         
2734         label = gtk_label_new (bufferf);
2735         gtk_container_add (GTK_CONTAINER (frame), label);
2736         gtk_widget_show (label);
2737         
2738         label = gtk_label_new (bufferl);
2739         gtk_notebook_append_page (GTK_NOTEBOOK (notebook), frame, label);
2740     }
2741     
2742     
2743     /* Ora aggiungiamo una pagina in una certa posizione */
2744     checkbutton = gtk_check_button_new_with_label ("Check me please!");
2745     gtk_widget_set_usize(checkbutton, 100, 75);
2746     gtk_widget_show (checkbutton);
2747     
2748     label = gtk_label_new ("Add spot");
2749     gtk_container_add (GTK_CONTAINER (checkbutton), label);
2750     gtk_widget_show (label);
2751     label = gtk_label_new ("Add page");
2752     gtk_notebook_insert_page (GTK_NOTEBOOK (notebook), checkbutton, label, 2);
2753     
2754     /* Ora finalmente aggiungiamo le pagine all'inizio */
2755     for (i=0; i < 5; i++) {
2756         sprintf(bufferf, "Prepend Frame %d", i+1);
2757         sprintf(bufferl, "PPage %d", i+1);
2758         
2759         frame = gtk_frame_new (bufferf);
2760         gtk_container_border_width (GTK_CONTAINER (frame), 10);
2761         gtk_widget_set_usize (frame, 100, 75);
2762         gtk_widget_show (frame);
2763         
2764         label = gtk_label_new (bufferf);
2765         gtk_container_add (GTK_CONTAINER (frame), label);
2766         gtk_widget_show (label);
2767         
2768         label = gtk_label_new (bufferl);
2769         gtk_notebook_prepend_page (GTK_NOTEBOOK(notebook), frame, label);
2770     }
2771     
2772     /* Stabilisce quale sar&agrave; la prima pagina che sar&agrave; visualizzata. */
2773     gtk_notebook_set_page (GTK_NOTEBOOK(notebook), 3);
2774     
2775     
2776     /* Crea un set di bottoni */
2777     button = gtk_button_new_with_label ("close");
2778     gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
2779                                GTK_SIGNAL_FUNC (destroy), NULL);
2780     gtk_table_attach_defaults(GTK_TABLE(table), button, 0,1,1,2);
2781     gtk_widget_show(button);
2782     
2783     button = gtk_button_new_with_label ("next page");
2784     gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
2785                                (GtkSignalFunc) gtk_notebook_next_page,
2786                                GTK_OBJECT (notebook));
2787     gtk_table_attach_defaults(GTK_TABLE(table), button, 1,2,1,2);
2788     gtk_widget_show(button);
2789     
2790     button = gtk_button_new_with_label ("prev page");
2791     gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
2792                                (GtkSignalFunc) gtk_notebook_prev_page,
2793                                GTK_OBJECT (notebook));
2794     gtk_table_attach_defaults(GTK_TABLE(table), button, 2,3,1,2);
2795     gtk_widget_show(button);
2796     
2797     button = gtk_button_new_with_label ("tab position");
2798     gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
2799                                (GtkSignalFunc) rotate_book, GTK_OBJECT(notebook));
2800     gtk_table_attach_defaults(GTK_TABLE(table), button, 3,4,1,2);
2801     gtk_widget_show(button);
2802     
2803     button = gtk_button_new_with_label ("tabs/border on/off");
2804     gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
2805                                (GtkSignalFunc) tabsborder_book,
2806                                GTK_OBJECT (notebook));
2807     gtk_table_attach_defaults(GTK_TABLE(table), button, 4,5,1,2);
2808     gtk_widget_show(button);
2809     
2810     button = gtk_button_new_with_label ("remove page");
2811     gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
2812                                (GtkSignalFunc) remove_book,
2813                                GTK_OBJECT(notebook));
2814     gtk_table_attach_defaults(GTK_TABLE(table), button, 5,6,1,2);
2815     gtk_widget_show(button);
2816     
2817     gtk_widget_show(table);
2818     gtk_widget_show(window);
2819     
2820     gtk_main ();
2821     
2822     return 0;
2823 }
2824 </verb></tscreen>
2825 <p>
2826 E speriamo che questo vi aiuti a creare i Blocco Note per le vostre applicazioni GTK!
2827
2828 <sect1> Finestre Scorribili (Scrolled Windows)
2829 <p>
2830 Le Finestre Scorribili sono usate per creare areee scorribili in una vera finestra.
2831 Si pu&ograve; inserire qualsiasi tipo di widget in questo tipo di finestra, e possono poi 
2832 essere accessibili a prescindere dalle dimensioni usando le barre di scorrimento.
2833
2834 La funzione seguente &egrave; usata per creare una nuova scrolled window.
2835
2836 <tscreen><verb>
2837 GtkWidget* gtk_scrolled_window_new (GtkAdjustment *hadjustment,
2838                                     GtkAdjustment *vadjustment);
2839 </verb></tscreen>
2840 <p>
2841 Il primo argomento &egrave; l'aggiustamento (di quanto scendere ogni
2842 volta) orizzontale e il secondo &egrave; quello verticale.  A questi si assegna
2843 quasi sempre il valore NULL.
2844
2845 <tscreen><verb>
2846 void gtk_scrolled_window_set_policy      (GtkScrolledWindow *scrolled_window,
2847                                           GtkPolicyType      hscrollbar_policy,
2848                                           GtkPolicyType      vscrollbar_policy);
2849 </verb></tscreen>
2850
2851 Questa funzione stabilisce la politica da usare nella barra di scorrimento. Il primo
2852 argomento &egrave; la finestra scorribile interessata. Il secondo stabilisce la politica
2853 per la barra di scorrimento orizzontale e il terzo &egrave; quello per la politca verticale.
2854
2855 La politica pu&ograve; essere GTK_POLICY AUTOMATIC o GTK_POLICY_ALWAYS.
2856 GTK_POLICY_AUTOMATIC decide automaticamente se la barra di scorrimento deve essere
2857 visualizzata, mentre con GTK_POLICY_ALWAYS la barra verr&agrave; sempre mostrata.
2858
2859 <tscreen><verb>
2860 #include <gtk/gtk.h>
2861
2862 void destroy(GtkWidget *widget, gpointer *data)
2863 {
2864     gtk_main_quit();
2865 }
2866
2867 int main (int argc, char *argv[])
2868 {
2869     static GtkWidget *window;
2870     GtkWidget *scrolled_window;
2871     GtkWidget *table;
2872     GtkWidget *button;
2873     char buffer[32];
2874     int i, j;
2875     
2876     gtk_init (&amp;argc, &amp;argv);
2877     
2878     /* Crea una nuove finestra di dialogo in cui la scrolled window sar&agrave; 
2879         inserita. Una finestra di dialogo &egrave; semplicemente come una 
2880         finestra normale, ma ha anche un vbox e un separatore orizzontale 
2881         gi&agrave; inseriti per difetto. E'un modo semplice per
2882         creare finestre di dialogo. */
2883     window = gtk_dialog_new ();
2884     gtk_signal_connect (GTK_OBJECT (window), "destroy",
2885                         (GtkSignalFunc) destroy, NULL);
2886     gtk_window_set_title (GTK_WINDOW (window), "dialog");
2887     gtk_container_border_width (GTK_CONTAINER (window), 0);
2888     
2889     /* crea una nuova finestra scorribile. */
2890     scrolled_window = gtk_scrolled_window_new (NULL, NULL);
2891     
2892     gtk_container_border_width (GTK_CONTAINER (scrolled_window), 10);
2893     
2894     /* la politica &egrave; GTK_POLICY AUTOMATIC per lo scorrimento orizzontale e 
2895         GTK_POLICY_ALWAYS per quello verticale.  */
2896     gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
2897                                     GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
2898     
2899     /* La finestra di dialogo &egrave; creata con un vbox gi&agrave; inserito.*/
2900     gtk_box_pack_start (GTK_BOX (GTK_DIALOG(window)->vbox), scrolled_window, 
2901                         TRUE, TRUE, 0);
2902     gtk_widget_show (scrolled_window);
2903     
2904     /* crea una tablella di10 x 10. */
2905     table = gtk_table_new (10, 10, FALSE);
2906     
2907     /* setta lo spazio tra ogni cella di 10 pixel sia verticale sia orizzontale*/
2908     gtk_table_set_row_spacings (GTK_TABLE (table), 10);
2909     gtk_table_set_col_spacings (GTK_TABLE (table), 10);
2910     
2911     /* inserisce la tabella nella finestra scorribile*/
2912     gtk_container_add (GTK_CONTAINER (scrolled_window), table);
2913     gtk_widget_show (table);
2914     
2915     /* questo semplicemente crea una griglia di bottoni nella tabelle per
2916        dimostrare il comportamento della finestra scorribile */
2917     for (i = 0; i < 10; i++)
2918             for (j = 0; j < 10; j++) {
2919                 sprintf (buffer, "button (%d,%d)\n", i, j);
2920                 button = gtk_toggle_button_new_with_label (buffer);
2921                 gtk_table_attach_defaults (GTK_TABLE (table), button,
2922                                            i, i+1, j, j+1);
2923                 gtk_widget_show (button);
2924             }
2925     
2926     /* Aggiunge un bottone "close" alla fine della finestra */
2927     button = gtk_button_new_with_label ("close");
2928     gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
2929                                (GtkSignalFunc) gtk_widget_destroy,
2930                                GTK_OBJECT (window));
2931     
2932     /* questo fa s&igrave; che questo bottone sia quello predefinito */
2933     
2934     GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
2935     gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area), button, TRUE, TRUE, 0);
2936     
2937     /* Questo ottiene il bottone predefinito. Premendo semplicemente l'"enter" il
2938         bottone si avvier&agrave; */
2939     gtk_widget_grab_default (button);
2940     gtk_widget_show (button);
2941     
2942     gtk_widget_show (window);
2943     
2944     gtk_main();
2945     
2946     return(0);
2947 }
2948 </verb></tscreen>
2949 <p>
2950 Prova a giocare con il ridemensionamento della finestra. Noterete la reazione della
2951 barra di scorrimento. Potete anche usare la funzione gtk_widget_set_usize() per
2952 assegnare la dimensione predefinita della finestra o di un widget.
2953 <!-- (ndMichel: questa chiamata non funziona per i bottoni!) -->
2954
2955
2956 <sect> Il Widgets Lista
2957 <p>
2958 Il widget GtkList serve come contenitore verticale per altri widget che
2959 devono essere di tipo GtkListItem.
2960
2961 Un widget GtkList possiede una sua propria finestra per ricevere eventi
2962 e un suo proprio colore di sfondo che di solito &egrave; bianco. Dal momento
2963 che &egrave; direttamente derivato dal widget GtkContainer, pu&ograve; essere trattato
2964 come tale usando la macro GTK_CONTAINER(List); si veda il widget GtkContainer
2965 per ulteriori dettagli.
2966 Per usare il widget GtkList in tutte le sue potenzialit&agrave;, si dovrebbe essere
2967 gi&agrave; familiari con l'uso della GList e delle relative funzioni g_list_*().
2968
2969 All'interno della definizione della struttura del widget GtkList c'&egrave; un
2970 campo che sar&agrave; per noi di grande interesse, cio&egrave;:
2971
2972 <tscreen><verb>
2973 struct _GtkList
2974 {
2975   ...
2976   GList *selection;
2977   guint selection_mode;
2978   ...
2979 }; 
2980 </verb></tscreen>
2981
2982 Il campo ``selection'' in un GtkList punta a una lista collegata di tutti
2983 gli elementi che sono selezionati correntemente, oppure a NULL se la 
2984 selezione &egrave; vuota. Quindi, per avere informazioni sulla selezione corrente,
2985 leggiamo il campo GTK_LIST()->selection, senza per&ograve; modificarlo dal momento
2986 che i campi interni debbono essere gestiti dalle funzioni gtk_list_*(). 
2987
2988 Le modalit&agrave; di selezione in una GtkList, e quindi il contenuto di
2989 GTK_LIST()->selection, sono determinate dal campo selection_mode:
2990
2991 selection_mode pu&ograve; assumere uno dei seguenti valori:
2992 <itemize>
2993 <item> GTK_SELECTION_SINGLE - La selezione pu&ograve; essere o NULL oppure
2994                         un puntatore GList* per un singolo elemento
2995                         selezionato.
2996
2997 <item> GTK_SELECTION_BROWSE - La selezione &egrave; null se la lista non contiene
2998                         alcun widget o se ha solo widget non sensibili,
2999                         oppure pu&ograve; contenere un puntatore a una struttura
3000                         GList, e quindi esattamente un elemento di lista.
3001
3002 <item> GTK_SELECTION_MULTIPLE - La selezione &egrave; ``NULL'' se non &egrave; selezionato
3003                         alcun elemento di lista, oppure un puntatore GList al
3004                         primo elemento selezionato. Quello, a sua volta, punta
3005                         a una struttura GList per il secondo elemento selezionato
3006                         e cos&igrave; via.
3007
3008 <item> GTK_SELECTION_EXTENDED - La selezione &egrave; sempre NULL.
3009 </itemize>
3010 <p>
3011 Il valore per difetto &egrave;  GTK_SELECTION_MULTIPLE.
3012
3013 <sect1> Segnali
3014 <p>
3015 <tscreen><verb>
3016 void GtkList::selection_changed (GtkList *LIST)
3017 </verb></tscreen>
3018
3019 Questo segnale verr&agrave; invocato ogni volta che il campo di
3020 selezione di una GtkList &egrave; cambiato. Questo accade quando
3021 un figlio della GtkList viene selezionato o deselezionato.
3022
3023 <tscreen><verb>
3024 void GtkList::select_child (GtkList *LIST, GtkWidget *CHILD)
3025 </verb></tscreen>
3026
3027 Questo segnale viene invocato quando un fuglio di una GtkList
3028 sta per essere selezionato. Questo accade principalmente in
3029 occasione di chiamate a gtk_list_select_item() e gtk_list_select_child(),
3030 di pressioni di bottoni e a volte pu&ograve; venir fatto scattare indirettamente
3031 in altre occasioni, in cui vengono aggiunti o rimossi dei figli
3032 dalla GtkList.
3033
3034 <tscreen><verb>
3035 void GtkList::unselect_child (GtkList *LIST, GtkWidget *CHILD)
3036 </verb></tscreen>
3037
3038 Questo segnale viene invocato quando un figlio della GtkList sta
3039 per essere deselezionato. Ci&ograve; accade principalmente in occasione
3040 di chiamate a gtk_list_unselect_item() e gtk_list_unselect_child(),
3041 di pressioni di bottoni, e a volte pu&ograve; venir fatto scattare indirettamente
3042 in altre occasioni, in cui vengono aggiunti o rimossi dei figli
3043 dalla GtkList.
3044
3045 <sect1> Funzioni
3046 <p>
3047 <tscreen><verb>
3048 guint gtk_list_get_type (void)
3049 </verb></tscreen>
3050
3051 Restituisce l'identificatore di tipo `GtkList'.
3052
3053 <tscreen><verb>
3054 GtkWidget* gtk_list_new (void)
3055 </verb></tscreen>
3056
3057 Crea un nuovo oggetto `GtkList'. Il nuovo widget viene
3058 restituito sotto forma di un puntoatore ad un oggetto
3059 `GtkWidget&igrave;'. In caso di fallimento, viene ritornato NULL.
3060
3061 <tscreen><verb>
3062 void gtk_list_insert_items (GtkList *LIST, GList *ITEMS, gint POSITION)
3063 </verb></tscreen>
3064
3065 Inserisce degli elementi di lista nella LIST, a partire da
3066 POSITION. ITEMS ITEMS &egrave; una lista doppiamente collegata, in
3067 cui ci si aspetta che i puntatori di ogni nodo puntino a
3068 un GtkListItem appena creato. I nodi GList di ITEMS vengono
3069 assunti dalla LIST.
3070
3071 <tscreen><verb>
3072 void gtk_list_append_items (GtkList *LIST, GList *ITEMS)
3073 </verb></tscreen>
3074
3075 Inserisce elementi di lista proprio come gtk_list_insert_items(),
3076 ma alla fine della LIST. I nodi GList di ITEMS vengono
3077 assunti dalla LIST.
3078
3079 <tscreen><verb>
3080 void gtk_list_prepend_items (GtkList *LIST, GList *ITEMS)
3081 </verb></tscreen>
3082
3083 Inserisce elementi di lista proprio come gtk_list_insert_items(),
3084 ma al principio della LIST. I nodi GList di ITEMS vengono
3085 assunti dalla LIST.
3086
3087 <tscreen><verb>
3088 void gtk_list_remove_items (GtkList *LIST, GList *ITEMS)
3089 </verb></tscreen>
3090
3091 Rimuove degli elementi di lista dalla LIST. ITEMS &egrave; una lista
3092 doppiamente collegata in cui ci si aspetta che i puntatori di
3093 ogni nodo puntino a un figlio diretto di LIST. E' poi responsabilit&agrave;
3094 del chiamante di fare una chiamata a g_list_free(ITEMS). E' anche
3095 necessario che il chiamante distrugga lui stesso gli elementi della
3096 lista.
3097
3098 <tscreen><verb>
3099 void gtk_list_clear_items (GtkList *LIST, gint START, gint END)
3100 </verb></tscreen>
3101
3102 Rimuove e distrugge elementi di lista da LIST. Un widget ne &egrave;
3103 interessato se la sua posizione corrente all'interno di LIST &egrave; compreso
3104 fra START ed END.
3105
3106 <tscreen><verb>
3107 void gtk_list_select_item (GtkList *LIST, gint ITEM)
3108 </verb></tscreen>
3109
3110 Invoca il segnale GtkList::select_child per un elemento di lista
3111 specificato dalla sua posizione corrente all'interno di LIST.
3112
3113 <tscreen><verb>
3114 void gtk_list_unselect_item (GtkList *LIST, gint ITEM)
3115 </verb></tscreen>
3116
3117 Invoca il segnale GtkList::unselect_child per un elemento di lista
3118 specificato dalla sua posizione corrente all'interno di LIST.
3119
3120 <tscreen><verb>
3121 void gtk_list_select_child (GtkList *LIST, GtkWidget *CHILD)
3122 </verb></tscreen>
3123
3124 Invoca il segnale GtkList::select_child per uno specifico CHILD.
3125
3126 <tscreen><verb>
3127 void gtk_list_unselect_child (GtkList *LIST, GtkWidget *CHILD)
3128 </verb></tscreen>
3129
3130 Invoca il segnale GtkList::unselect_child per uno specifico CHILD.
3131
3132 <tscreen><verb>
3133 gint gtk_list_child_position (GtkList *LIST, GtkWidget *CHILD)
3134 </verb></tscreen>
3135
3136 Restituisce la posizione di CHILD all'interno di LIST. In caso di fallimento,
3137 viene restituito `-1'.
3138
3139 <tscreen><verb>
3140 void gtk_list_set_selection_mode (GtkList *LIST, GtkSelectionMode MODE)
3141 </verb></tscreen>
3142
3143 Assegna a LIST il modo di selezione MODE, che pu&ograve; essere uno fra 
3144 GTK_SELECTION_SINGLE, GTK_SELECTION_BROWSE, GTK_SELECTION_MULTIPLE o
3145 GTK_SELECTION_EXTENDED.
3146
3147 <tscreen><verb>
3148 GtkList* GTK_LIST (gpointer OBJ)
3149 </verb></tscreen>
3150
3151 Fa il cast di un generico puntatore a `GtkList*'. Per maggiori
3152 informazioni vedere Standard Macros::.
3153
3154 <tscreen><verb>
3155 GtkListClass* GTK_LIST_CLASS (gpointer CLASS)
3156 </verb></tscreen>
3157
3158 Fa il cast di un generico puntatore a `GtkListClass*'. Per maggiori
3159 informazioni vedere Standard Macros::.
3160
3161 <tscreen><verb>
3162 gint GTK_IS_LIST (gpointer OBJ)
3163 </verb></tscreen>
3164
3165 Determina se un generico puntatore si riferisce ad un oggetto `GtkList'.
3166 Per maggiori informazioni vedere Standard Macros::.
3167
3168
3169 <sect1> Esempio
3170 <p>
3171 Diamo di seguito un programma di esempio che stamper&agrave; i campbiamenti
3172 della selezione di una GtkList, e vi lascia ``imprigionare'' gli elementi
3173 di una lista selezionandoli con il pulsante destro del mouse:
3174
3175 <tscreen><verb>
3176 /* compilate questo programma con:
3177  * $ gcc -I/usr/local/include/ -lgtk -lgdk -lglib -lX11 -lm -Wall main.c
3178  */
3179
3180 /* includiamo i file header di gtk+
3181  * includiamo stdio.h, ne abbiamo bisogno per printf()
3182  */
3183 #include        <gtk/gtk.h>
3184 #include        <stdio.h>
3185
3186 /* Questa e' la nostra stringa di identificazione dei dati per assegnarli
3187  * ad elementi di lista
3188  */
3189 const   gchar   *list_item_data_key="list_item_data";
3190
3191
3192 /* prototipi per i gestori di segnale che connetteremo
3193  * al widget GtkList
3194  */
3195 static  void    sigh_print_selection    (GtkWidget      *gtklist,
3196                                          gpointer       func_data);
3197 static  void    sigh_button_event       (GtkWidget      *gtklist,
3198                                          GdkEventButton *event,
3199                                          GtkWidget      *frame);
3200
3201
3202 /* funzione main per predisporre l'interfaccia utente */
3203
3204 gint main (int argc, gchar *argv[])
3205 {                                  
3206     GtkWidget       *separator;
3207     GtkWidget       *window;
3208     GtkWidget       *vbox;
3209     GtkWidget       *scrolled_window;
3210     GtkWidget       *frame;
3211     GtkWidget       *gtklist;
3212     GtkWidget       *button;
3213     GtkWidget       *list_item;
3214     GList           *dlist;
3215     guint           i;
3216     gchar           buffer[64];
3217     
3218     
3219     /* inizializza gtk+ (e di conseguenza gdk) */
3220
3221     gtk_init(&amp;argc, &amp;argv);
3222     
3223     
3224     /* crea una finestra in cui mettere tutti i widget
3225      * connette gtk_main_quit() al segnale "destroy" della finestra
3226      * per gestire le richieste di chiusura finestra del window manager
3227      */
3228     window=gtk_window_new(GTK_WINDOW_TOPLEVEL);
3229     gtk_window_set_title(GTK_WINDOW(window), "GtkList Example");
3230     gtk_signal_connect(GTK_OBJECT(window),
3231                        "destroy",
3232                        GTK_SIGNAL_FUNC(gtk_main_quit),
3233                        NULL);
3234     
3235     
3236     /* all'interno della finestra abbiamo bisogno di una scatola
3237      * in cui mettere i widget verticalmente */
3238     vbox=gtk_vbox_new(FALSE, 5);
3239     gtk_container_border_width(GTK_CONTAINER(vbox), 5);
3240     gtk_container_add(GTK_CONTAINER(window), vbox);
3241     gtk_widget_show(vbox);
3242     
3243     /* questa &egrave; la finestra scorribile in cui mettere il widget GtkList */
3244     scrolled_window=gtk_scrolled_window_new(NULL, NULL);
3245     gtk_widget_set_usize(scrolled_window, 250, 150);
3246     gtk_container_add(GTK_CONTAINER(vbox), scrolled_window);
3247     gtk_widget_show(scrolled_window);
3248     
3249     /* crea il widget GtkList
3250      * connette il gestore di segnale sigh_print_selection()
3251      * al segnale "selection_changed" della GtkList, per stampare
3252      * gli elementi selezionati ogni volta che la selezione cambia
3253      */
3254     gtklist=gtk_list_new();
3255     gtk_container_add(GTK_CONTAINER(scrolled_window), gtklist);
3256     gtk_widget_show(gtklist);
3257     gtk_signal_connect(GTK_OBJECT(gtklist),
3258                        "selection_changed",
3259                        GTK_SIGNAL_FUNC(sigh_print_selection),
3260                        NULL);
3261     
3262     /* creiamo una "Prigione" (Prison) in cui mettere gli elementi di lista ;)
3263      */
3264     frame=gtk_frame_new("Prison");
3265     gtk_widget_set_usize(frame, 200, 50);
3266     gtk_container_border_width(GTK_CONTAINER(frame), 5);
3267     gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_OUT);
3268     gtk_container_add(GTK_CONTAINER(vbox), frame);
3269     gtk_widget_show(frame);
3270     
3271     /* connette il gestore di segnale sigh_button_event() alla GtkList
3272      * il quale gestira' l'"imprigionamento" degli elementi di lista
3273      */
3274     gtk_signal_connect(GTK_OBJECT(gtklist),
3275                        "button_release_event",
3276                        GTK_SIGNAL_FUNC(sigh_button_event),
3277                        frame);
3278     
3279     /* crea un separatore
3280      */
3281     separator=gtk_hseparator_new();
3282     gtk_container_add(GTK_CONTAINER(vbox), separator);
3283     gtk_widget_show(separator);
3284     
3285     /* infine creiamo un bottone e connettiamone il segnale "clicked"
3286      * alla distruzione della finestra
3287      */
3288     button=gtk_button_new_with_label("Close");
3289     gtk_container_add(GTK_CONTAINER(vbox), button);
3290     gtk_widget_show(button);
3291     gtk_signal_connect_object(GTK_OBJECT(button),
3292                               "clicked",
3293                               GTK_SIGNAL_FUNC(gtk_widget_destroy),
3294                               GTK_OBJECT(window));
3295     
3296     
3297     /* a questo punto creiamo 5 elementi di lista, ognuno con la
3298      * propria etichetta, e li aggiungiamo alla GtkList usando
3299      * gtk_container_add(). Inoltre, recuperiamo la stringa di testo
3300      * dall'etichetta e la associamo, per ogni elemento, a
3301      * list_item_data_key
3302      */
3303     for (i=0; i<5; i++) {
3304         GtkWidget       *label;
3305         gchar           *string;
3306         
3307         sprintf(buffer, "ListItemContainer with Label #%d", i);
3308         label=gtk_label_new(buffer);
3309         list_item=gtk_list_item_new();
3310         gtk_container_add(GTK_CONTAINER(list_item), label);
3311         gtk_widget_show(label);
3312         gtk_container_add(GTK_CONTAINER(gtklist), list_item);
3313         gtk_widget_show(list_item);
3314         gtk_label_get(GTK_LABEL(label), &amp;string);
3315         gtk_object_set_data(GTK_OBJECT(list_item),
3316                             list_item_data_key,
3317                             string);
3318     }
3319
3320     /* qui creiamo altre 5 etichette, questa volta usando
3321      * per la creazione gtk_list_item_new_with_label().
3322      * Non possiamo recuperare la stringa di testo dall'etichetta
3323      * dal momento che non disponiamo di puntatori alle etichette,
3324      * quindi associamo semplicemente il list_item_data_key di ogni
3325      * elemento di lista con la medesima stringa di testo.
3326      * Per aggiungere elementi di lista, li mettiamo tutti in una lista
3327      * doppiamente collegata (GList), e quindi li aggiungiamo con una
3328      * unica chiamata a gtk_list_append_items().
3329      * Dal momento che usiamo g_list_prepend() per mettere gli elementi
3330      * nella lista doppiamente collegata, il loro ordine sara' discendente
3331      * (invece che ascendente come sarebbe se usassimo g_list_append())
3332      */
3333     dlist=NULL;
3334     for (; i<10; i++) {
3335         sprintf(buffer, "List Item with Label %d", i);
3336         list_item=gtk_list_item_new_with_label(buffer);
3337         dlist=g_list_prepend(dlist, list_item);
3338         gtk_widget_show(list_item);
3339         gtk_object_set_data(GTK_OBJECT(list_item),
3340                             list_item_data_key,
3341                             "ListItem with integrated Label");
3342     }
3343     gtk_list_append_items(GTK_LIST(gtklist), dlist);
3344     
3345     /* e finalmente vogliamo vedere la finestra, non e' vero? ;)
3346      */
3347     gtk_widget_show(window);
3348     
3349     /* lancia il ciclo principale di gtk
3350      */
3351     gtk_main();
3352     
3353     /* si arriva a questo punto dopo la chiamata di gtk_main_quit(),
3354      * il che accade quando viene distrutta la finestra principale
3355      */
3356     return 0;
3357 }
3358
3359 /* questo e' il gestore di segnale che e' stato connesso all'evento di
3360  * pressione/rilascio del bottone della GtkList
3361  */
3362 void
3363 sigh_button_event       (GtkWidget      *gtklist,
3364                          GdkEventButton *event,
3365                          GtkWidget      *frame)
3366 {
3367     /* facciamo qualcosa solo nel caso di rilascio del terzo bottone
3368      * (quello piu' a destra)
3369      */
3370     if (event->type==GDK_BUTTON_RELEASE &amp;&amp;
3371         event->button==3) {
3372         GList           *dlist, *free_list;
3373         GtkWidget       *new_prisoner;
3374         
3375         /* recuperiamo l'elemento di lista selezionato correntemente,
3376          * che sara' il nostro prossimo prigioniero ;)
3377          */
3378         dlist=GTK_LIST(gtklist)->selection;
3379         if (dlist)
3380                 new_prisoner=GTK_WIDGET(dlist->data);
3381         else
3382                 new_prisoner=NULL;
3383         
3384         /* cerchiamo elementi di lista gia' imprigionati,
3385          * li rimetteremo nella lista.
3386          * Ricordare di liberare la lista doppiamente collegata
3387          * che viene restituita da gtk_container_children()
3388          */
3389         dlist=gtk_container_children(GTK_CONTAINER(frame));
3390         free_list=dlist;
3391         while (dlist) {
3392             GtkWidget       *list_item;
3393             
3394             list_item=dlist->data;
3395             
3396             gtk_widget_reparent(list_item, gtklist);
3397             
3398             dlist=dlist->next;
3399         }
3400         g_list_free(free_list);
3401         
3402         /* se abbiamo un nuovo prigioniero, lo rimuoviamo
3403          * dalla GtkList e lo mettiamo nella cornice della
3404          * "Prigione". Dobbiamo prima deselezionare l'elemento
3405          */
3406         if (new_prisoner) {
3407             GList   static_dlist;
3408             
3409             static_dlist.data=new_prisoner;
3410             static_dlist.next=NULL;
3411             static_dlist.prev=NULL;
3412             
3413             gtk_list_unselect_child(GTK_LIST(gtklist),
3414                                     new_prisoner);
3415             gtk_widget_reparent(new_prisoner, frame);
3416         }
3417     }
3418 }
3419
3420 /* questo e' il gestore di segnaleche viene chiamato de la
3421  * GtkList emette il segnale "selection_changed"
3422  */
3423 void
3424 sigh_print_selection    (GtkWidget      *gtklist,
3425                          gpointer       func_data)
3426 {
3427     GList   *dlist;
3428     
3429     /* recuperiamo la lista doppiamente collegata degli
3430      * elementi selezionati della GtkList, ricordate di
3431      * trattarla come sola lettura
3432      */
3433     dlist=GTK_LIST(gtklist)->selection;
3434     
3435     /* se non ci sono elementi selezionati non c'e' altro da
3436      * fare che dirlo all'utente
3437      */
3438     if (!dlist) {
3439         g_print("Selection cleared\n");
3440         return;
3441     }
3442     /* ok, abbiamo una selezione e quindi lo scriviamo
3443      */
3444     g_print("The selection is a ");
3445     
3446     /* ottieniamo l'elemento di lista dalla lista doppiamente
3447      * collegata e poi richiediamo i dati associati con
3448      *  list_item_data_key. Poi semplicemente li stampiamo
3449      */
3450     while (dlist) {
3451         GtkObject       *list_item;
3452         gchar           *item_data_string;
3453         
3454         list_item=GTK_OBJECT(dlist->data);
3455         item_data_string=gtk_object_get_data(list_item,
3456                                              list_item_data_key);
3457         g_print("%s ", item_data_string);
3458         
3459         dlist=dlist->next;
3460     }
3461     g_print("\n");
3462 }
3463 </verb></tscreen>
3464
3465 <sect1> Il Widget Elemento di Lista (List Item)
3466 <p>
3467 Il widget GtkListItem &egrave; progettato allo scopo di essere un contenitore
3468 collegato ad un figlio, per fornire le funzioni per la selezione e deselezione
3469 allo stesso modo in cui il widget GtkList ne ha bisogno per i propri figli.
3470
3471 Un GtkListItem ha la sua propria finestra per ricevere eventi, e ha il suo
3472 proprio colore di sfondo, che di solito &egrave; bianco.
3473
3474 Dal momento che questo widget deriva direttamente da GtkItem, pu&ograve; essere
3475 trattato come tale usando la macro GTK_ITEM(ListItem), vedere il widget
3476 GtkItem per ulteriori informazioni.
3477 Di solito un GtkListItem ha solo un'etichetta per identificare per esempio
3478 un nome di file all'interno di una GtkList -- per cui viene fornita la
3479 funzione appropriata gtk_list_item_new_with_label(). Si pu&ograve; ottenere lo
3480 stesso effetto creando una GtkLabel da sola, assegnando al suo allineamento
3481 i valori xalign=0 e yalign=0.5, aggiungendo successivamente un contenitore
3482 alla GtkListItem.
3483
3484 Dal momento che non si &egrave; obbligati a mettere una GtkLabel, si pu&ograve; anche
3485 aggiungere una GtkVBox  una GtkArrow ecc. alla GtkListItem.
3486
3487 <sect1> Segnali
3488 <p>
3489 Un GtkListItem non crea alcun nuovo segnale di per se, ma eredita
3490 i segnali di GtkItem. Per ulteriori informazioni, vedere GtkItem::.
3491
3492
3493 <sect1> Funzioni
3494 <p>
3495
3496 <tscreen><verb>
3497 guint gtk_list_item_get_type (void)
3498 </verb></tscreen>
3499
3500 Restituisce l'identificatore di tipo `GtkListItem'.
3501
3502 <tscreen><verb>
3503 GtkWidget* gtk_list_item_new (void)
3504 </verb></tscreen>
3505
3506 Crea un nuovo oggetto `GtkListItem'. Il nuovo widget viene restituito
3507 sottoforma di un puntatore ad un oggetto `GtkWidget'. In caso di 
3508 fallimento, viene restituito `NULL'.
3509
3510 <tscreen><verb>
3511 GtkWidget* gtk_list_item_new_with_label (gchar *LABEL)
3512 </verb></tscreen>
3513
3514 Cre un nuovo oggetto `GtkListItem', avente come unico figlio
3515 un GtkLabel.  Il nuovo widget viene restituito
3516 sottoforma di un puntatore ad un oggetto `GtkWidget'. In caso di 
3517 fallimento, viene restituito `NULL'.
3518
3519 <tscreen><verb>
3520 void gtk_list_item_select (GtkListItem *LIST_ITEM)
3521 </verb></tscreen>
3522
3523 Questa funzione &egrave; essenzialmente un wrapper per una chiamata a
3524 gtk_item_select (GTK_ITEM (list_item)) che emetter&agrave; il segnale
3525 GtkItem::select.
3526 Vedere GtkItem:: per maggiori informazioni.
3527
3528 <tscreen><verb>
3529 void gtk_list_item_deselect (GtkListItem *LIST_ITEM)
3530 </verb></tscreen>
3531
3532 Questa funzione &egrave; essenzialmente un wrapper per una chiamata a
3533 gtk_item_deselect (GTK_ITEM (list_item)) che emetter&agrave; il segnale
3534 GtkItem::deselect.
3535 Vedere GtkItem:: per maggiori informazioni.
3536
3537 <tscreen><verb>
3538 GtkListItem* GTK_LIST_ITEM (gpointer OBJ)
3539 </verb></tscreen>
3540
3541 Effettua il cast di un puntatore generico a `GtkListItem*'. Vedere
3542 Standard Macros:: per maggiorni informazioni.
3543
3544 <tscreen><verb>
3545 GtkListItemClass* GTK_LIST_ITEM_CLASS (gpointer CLASS)
3546 </verb></tscreen>
3547
3548 Effettua il cast di un puntatore generico a `GtkListItemClass*'. Vedere
3549 Standard Macros:: per maggiorni informazioni.
3550
3551 <tscreen><verb>
3552 gint GTK_IS_LIST_ITEM (gpointer OBJ)
3553 </verb></tscreen>
3554
3555 Determina se un puntatore generico si riferisce ad un oggetto
3556 `GtkListItem'. Vedere Standard Macros:: per maggiorni informazioni.
3557  
3558 <sect1> Esempio
3559 <p>
3560 Come esempio su questo argomento, si veda quello relativo alla GtkList,
3561 che riguarda anche l'uso del GtkListItem.
3562
3563 <sect> Selezione di File (File Selections)
3564 <p>
3565
3566 Il widget Selezione di File &egrave; un modo rapido e semplice per mostrare una
3567 finestra di dialogo `File'. Questa si presenta completa di bottoni Ok,
3568 Cancel e Help, un buon modo per tagliare i tempi di programmazione.
3569
3570 Per creare una nuova finestra di selezione file usate:
3571
3572 <tscreen><verb>
3573 GtkWidget* gtk_file_selection_new (gchar *title);
3574 </verb></tscreen>
3575
3576 Per assegnare il nome del file, ad esempio per predisporre una certa
3577 directory o per dare un certo nome di file per difetto, usate la seguente
3578 funzione:
3579
3580 <tscreen><verb>
3581 void gtk_file_selection_set_filename (GtkFileSelection *filesel, gchar *filename);
3582 </verb></tscreen>
3583
3584 Per recuperare il testo che l'utente ha inserito o che ha selezionato con
3585 il mouse, si usa la funzione:
3586
3587 <tscreen><verb>
3588 gchar* gtk_file_selection_get_filename (GtkFileSelection *filesel);
3589 </verb></tscreen>
3590
3591 Ci sono anche dei puntatori ai widget che sono contenuti all'interno
3592 del widget di selezione file. Si tratta di:
3593
3594 <itemize>
3595 <item>dir_list
3596 <item>file_list
3597 <item>selection_entry
3598 <item>selection_text
3599 <item>main_vbox
3600 <item>ok_button
3601 <item>cancel_button
3602 <item>help_button
3603 </itemize>
3604
3605 Molto probabilmente potreste voler usare i puntatori a ok_button,
3606 cancel_button e help_button per segnalarne l'uso.
3607
3608 Ecco un esempio rubato da testgtk.c, nodificato per essere eseguito da
3609 solo. Come potrete vedere, non c'&egrave; molto pi&ugrave; che la creazione di un
3610 widget di selezione file. In questo esempio, il bottone Help non fa nulla
3611 mentre &egrave; mostrato allo schermo, dal momento che non c'&egrave; alcun segnale
3612 collegato con esso. 
3613
3614 <tscreen><verb>
3615 #include <gtk/gtk.h>
3616
3617 /* Recupera il nome di file selezionato e stampalo a console */
3618 void file_ok_sel (GtkWidget *w, GtkFileSelection *fs)
3619 {
3620     g_print ("%s\n", gtk_file_selection_get_filename (GTK_FILE_SELECTION (fs)));
3621 }
3622
3623 void destroy (GtkWidget *widget, gpointer *data)
3624 {
3625     gtk_main_quit ();
3626 }
3627
3628 int main (int argc, char *argv[])
3629 {
3630     GtkWidget *filew;
3631     
3632     gtk_init (&amp;argc, &amp;argv);
3633     
3634     /* Crea un nuovo widget di selezione file */
3635     filew = gtk_file_selection_new ("File selection");
3636     
3637     gtk_signal_connect (GTK_OBJECT (filew), "destroy",
3638                         (GtkSignalFunc) destroy, &amp;filew);
3639     /* Connette ok_button alla funzione file_ok_sel */
3640     gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (filew)->ok_button),
3641                         "clicked", (GtkSignalFunc) file_ok_sel, filew );
3642     
3643     /* Connette cancel_button alla funzione di distruzione del widget */
3644     gtk_signal_connect_object (GTK_OBJECT (GTK_FILE_SELECTION (filew)->cancel_button),
3645                                "clicked", (GtkSignalFunc) gtk_widget_destroy,
3646                                GTK_OBJECT (filew));
3647     
3648     /* Preassegnamo un nome di file, come se stessimo dando un valore per difetto in 
3649     dialogo di tipo `` salva con nome '' */
3650     gtk_file_selection_set_filename (GTK_FILE_SELECTION(filew), 
3651                                      "penguin.png");
3652     
3653     gtk_widget_show(filew);
3654     gtk_main ();
3655     return 0;
3656 }
3657 </verb></tscreen>
3658
3659 <sect>Il Widget Men&ugrave; (Menu Widgets)
3660 <p>
3661 Ci sono due modi per creare dei men&ugrave;, quello facile e quello difficile.
3662 Ognuno &egrave; pi&ugrave; adatto per certe circostanze, ma di solito si pu&ograve; usare il
3663 modo semplice, cio&eacute; menu_factory (la ``fabbrica dei men&ugrave;''). Il modo 
3664 ``difficile'' &egrave; di crearsi tutti i men&ugrave; usando direttamente le chiamate.
3665 Quello semplice &egrave; di usare le chiamate di tipo gtk_menu_factory. Anche se
3666 &egrave; un modo molto pi&ugrave; semplice, ci sono svantaggi e vantaggi per ciascuno
3667 dei due approcci.
3668
3669 La menufactory &egrave; molto pi&ugrave; semplice da usare e per aggiungere dei nuovi
3670 men&ugrave;, anche se scriversi un po' di funzioni per creare dei men&ugrave; con il
3671 metodo manuale pu&ograve; dare risultati molto migliori dal punto di vista 
3672 dell'usabilit&agrave;. Con la menufactory, non &egrave; possibile mettere immagini o
3673 segni '/' nei men&ugrave;.
3674 <p>
3675 <sect1>Creazione Manuale di Men&ugrave;
3676 <p>
3677 Seguendo la tradizionale arte dell'insegnamento, partiamo dal modo
3678 difficile. <tt>:)</>
3679 <p>
3680 Diamo un'occhiata alle funzioni usate per creare dei men&ugrave;.
3681 Con questa prima funzione si crea un nuovo men&ugrave;:
3682
3683 <tscreen><verb>
3684 GtkWidget *gtk_menu_bar_new()
3685 </verb></tscreen>
3686
3687 Questa funzione crea una nuova barra di men&ugrave;. Per impacchettarla in una
3688 finestra o si usa la funzione gtk_container_add, oppure, per impacchettarla
3689 in una scatola, le funzioni box_pack - come con i bottoni.
3690
3691 <tscreen><verb>
3692 GtkWidget *gtk_menu_new();
3693 </verb></tscreen>
3694
3695 Questa funzione restituisce un puntatore ad un nuovo men&ugrave;, non viene mai
3696 realmente mostrato (con gtk_widget_show), serve solo per contenere gli
3697 elementi del men&ugrave;. Spero che il tutto risulti pi&ugrave; chiaro quando dare
3698 un'occhiata all'esempio pi&ugrave; sotto.
3699 <p>
3700 Le prossime due chiamate sono usate per creare degli elementi che poi
3701 vengono impacchettati nel men&ugrave;.
3702
3703 <tscreen><verb>
3704 GtkWidget *gtk_menu_item_new()
3705 </verb></tscreen>
3706
3707 e
3708
3709 <tscreen><verb>
3710 GtkWidget *gtk_menu_item_new_with_label(const char *label)
3711 </verb></tscreen>
3712
3713 Queste chiamate sono usate per creare i menu che devono essere mostrati.
3714 Ricordate la differenza che esiste fra un ``men&ugrave;'' come quelli creati con
3715 gtk_menu_new e un ``elemento di men&ugrave;'' (menu item) come quelli creati con
3716 la funzione creata con gtk_menu_item_new. L'elemento di men&ugrave; sar&agrave; un bottone
3717 vero e proprio con una azione associata, mentre un men&ugrave; &egrave; solo un contenitore
3718 che li raccoglie.
3719
3720 <tscreen><verb>
3721 gtk_menu_item_append()
3722
3723 gtk_menu_item_set_submenu()
3724 </verb></tscreen>
3725
3726 Le funzioni gtk_menu_item_new_with_label e gtk_menu_item_new si comportano esattamente come
3727 vi aspettereste dopo aver visto le funzioni che riguardano i bottoni. La prima
3728 crea un elemento di men&ugrave; con un'etichetta gi&agrave; applicata, mentre la seconda crea
3729 un nuovo elemento di men&ugrave; vuoto.
3730 <p>
3731 Ecco i passi necessari per creare una barra di men&ugrave; con i relativi men&ugrave; collegati:
3732 <itemize>
3733 <item>  Create un nuovo men&ugrave; con gtk_menu_new()
3734 <item>  Create un elementoa di men&ugrave; con using gtk_menu_item_new(). Questo  rappresenta
3735   la base del men&ugrave;, e il testo che appare qui sar&agrave; sulla barra stessa.
3736 <item>  Usate delle chiamate multiple a gtk_menu_item_new() per ognuno degli
3737   elementi che volete mettere nel vostro men&ugrave;. Usate inoltre gtk_menu_item_append()
3738   per mettere assieme ognuno di questi nuovo elementi. Si crea cos&igrave; una lista di
3739   elementi di men&ugrave;.
3740 <item>  Usate gtk_menu_item_set_submenu() per attaccare gli elementi di men&ugrave;
3741   creati all'elemento di men&ugrave; base (quello creato nel secondo passaggio).
3742 <item>  Create una nuova barra di men&ugrave; usando gtk_menu_bar_new. Questo passo
3743   necessita di essere effettuato una sola volta quando si crea una serie di
3744   men&ugrave; su una serie di men&ugrave; su una sola barra.
3745 <item> Usate gtk_menu_bar_append per mettere il men&ugrave; base sulla barra dei men&ugrave;.
3746 </itemize>
3747 <p>
3748 Creare un men&ugrave; a comparsa &egrave; pi&ugrave; o meno la stessa cosa. La differenza &egrave; che il
3749 il men&ugrave; non viene attivato ``automaticamente'' da una barra, bens&igrave; esplicitamente
3750 con la chiamata alla funzione gtk_menu_popup() da un evento di pressione di
3751 un pulsante.
3752 Seguite questi passaggi:
3753 <itemize>
3754 <item>Create una funzione di gestione di un evento. Essa deve seguire il prototipo
3755 <tscreen>
3756 static gint handler(GtkWidget *widget, GdkEvent *event);
3757 </tscreen>
3758 e usare l'evento per scoprire dove il menu deve essere fatto comparire.
3759 <item>Nel gestore di evento, se questo &egrave; la pressione di un bottone, trattate
3760 <tt>event</tt> come l'evento relativo ad un bottone (cosa che in effetti &egrave;)
3761 e usatelo come mostrato nel codice di esempio per passare informazioni a
3762 gtk_menu_popup().
3763 <item>Collegate il gestore di evento a un widget con
3764 <tscreen>
3765 gtk_signal_connect_object(GTK_OBJECT(widget), "event",
3766                           GTK_SIGNAL_FUNC (handler), GTK_OBJECT(menu));
3767 </tscreen>
3768 in cui <tt>widget</tt> &egrave; il widget a cui state effettuando il collegamento, e
3769 <tt>handler</tt> &egrave; la funzione di gestione, mentre <tt>menu</tt> &egrave; un men&ugrave;
3770 creato con gtk_menu_new(). Quest'ultimo pu&ograve; essere un men&ugrave; che viene anche
3771 attivato da una barra di men&ugrave;, come mostrato nel codice di esempio.
3772 </itemize>
3773 <p>
3774 <sect1>Esempio di Men&ugrave; Manuale
3775 <p>
3776 Per la teoria dovrebbe essere abbastanza. Diamo un'occhiata ad un esempio che
3777 ci aiuti a chiarire le cose.
3778
3779 <tscreen><verb>
3780
3781 #include <gtk/gtk.h>
3782
3783 static gint button_press (GtkWidget *, GdkEvent *);
3784 static void menuitem_response (gchar *);
3785
3786
3787 int main (int argc, char *argv[])
3788 {
3789
3790     GtkWidget *window;
3791     GtkWidget *menu;
3792     GtkWidget *menu_bar;
3793     GtkWidget *root_menu;
3794     GtkWidget *menu_items;
3795     GtkWidget *vbox;
3796     GtkWidget *button;
3797     char buf[128];
3798     int i;
3799
3800     gtk_init (&amp;argc, &amp;argv);
3801
3802     /* crea una nuova finestra */
3803     window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
3804     gtk_window_set_title(GTK_WINDOW (window), "GTK Menu Test");
3805     gtk_signal_connect(GTK_OBJECT (window), "delete_event",
3806                        (GtkSignalFunc) gtk_exit, NULL);
3807
3808     /* Inizializziamo il men&ugrave;, e ricordate: mai applicare
3809      * gtk_show_widget() al widget men&ugrave;!!
3810      * Questo &egrave; il men&ugrave; che contiene gli elementi, quello che
3811      * spunta quando si fa click sul "Men&ugrave; radice" nell'applicazione */
3812     menu = gtk_menu_new();
3813
3814     /* Questo &egrave; il men&ugrave; radice, e l'etichetta sar&agrave; il nome del men&ugrave; che
3815      * verr&agrave; mostrato sulla barra dei men&ugrave;. Non ci sar&agrave; alcun gestore di
3816      * segnale collegato, dal momento che non fa altro che mostrare il resto
3817      * del men&ugrave; quando viene premuto. */
3818     root_menu = gtk_menu_item_new_with_label("Root Menu");
3819
3820     gtk_widget_show(root_menu);
3821
3822     /* Ora creiamo un ciclo che crea tre elementi di menu per "test-menu".
3823      * Notete la chiamata a gtk_menu_append. In questo punto aggiungiamo una
3824      * lista di elementi al nostro men&ugrave;. Normalmente, dovremmo poi catturare
3825      * il segnale di attivazione per ognuno degli elementi del menu, e creare
3826      * una funzione di ritorno per ciascuno di essi, ma qui non li mettiamo per
3827      * brevit&agrave;. */
3828
3829     for(i = 0; i < 3; i++)
3830         {
3831             /* Copia i nomi in buf. */
3832             sprintf(buf, "Test-undermenu - %d", i);
3833
3834             /* Crea un nuovo elemento di men&ugrave; con un nome... */
3835             menu_items = gtk_menu_item_new_with_label(buf);
3836
3837             /* ...e aggiungilo al men&ugrave;. */
3838             gtk_menu_append(GTK_MENU (menu), menu_items);
3839
3840             /* Fa qualcosa di interessante quando si seleziona l'elemento */
3841             gtk_signal_connect_object(GTK_OBJECT(menu_items), "activate",
3842                 GTK_SIGNAL_FUNC(menuitem_response), (gpointer) g_strdup(buf));
3843
3844             /* Mostra il widget */
3845             gtk_widget_show(menu_items);
3846         }
3847
3848     /* Ora specifichiamo che vogliamo che il men&ugrave; che abbiamo appena creato
3849      * sia il men&ugrave; radice *//
3850     gtk_menu_item_set_submenu(GTK_MENU_ITEM (root_menu), menu);
3851
3852     /* Una vbox in cui mettere un men&ugrave; ed un bottone: */
3853     vbox = gtk_vbox_new(FALSE, 0);
3854     gtk_container_add(GTK_CONTAINER(window), vbox);
3855     gtk_widget_show(vbox);
3856
3857     /* Crea una barra dei men&ugrave; per metterci i men&ugrave; e l'aggiunge alla finestra principale */
3858     menu_bar = gtk_menu_bar_new();
3859     gtk_box_pack_start(GTK_BOX(vbox), menu_bar, FALSE, FALSE, 2);
3860     gtk_widget_show(menu_bar);
3861
3862     /* Crea un bottone a cui collegare un men&ugrave; */
3863     button = gtk_button_new_with_label("press me");
3864     gtk_signal_connect_object(GTK_OBJECT(button), "event",
3865         GTK_SIGNAL_FUNC (button_press), GTK_OBJECT(menu));
3866     gtk_box_pack_end(GTK_BOX(vbox), button, TRUE, TRUE, 2);
3867     gtk_widget_show(button);
3868
3869     /* E finalmente attacchiamo l'elemento di men&ugrave; alla barra dei men&ugrave; -- questo
3870      * &egrave; l'elemento di men&ugrave; "radice" di cui parlavo */
3871     gtk_menu_bar_append(GTK_MENU_BAR (menu_bar), root_menu);
3872
3873     /* La finestra va mostrata sempre come ultimo passo in modo che sia gi&agrave;
3874      * completa di tutti i suoi elementi. */
3875     gtk_widget_show(window);
3876
3877     gtk_main ();
3878
3879     return 0;
3880 }
3881
3882
3883
3884 /* Risponde alla pressione di un bottone impostando un men&ugrave; che
3885  * viene passato come widget.
3886  * Notate che l'argomento "widget" si riferisce al men&ugrave; impostato
3887  * e NON al bottone premuto.
3888  */
3889
3890 static gint button_press (GtkWidget *widget, GdkEvent *event)
3891 {
3892
3893     if (event->type == GDK_BUTTON_PRESS) {
3894         GdkEventButton *bevent = (GdkEventButton *) event; 
3895         gtk_menu_popup (GTK_MENU(widget), NULL, NULL, NULL, NULL,
3896                         bevent->button, bevent->time);
3897         /* Riferisce al codice chiamante che abbiamo trattato l'evento;
3898          * la faccenda finisce qui. */
3899         return TRUE;
3900     }
3901
3902     /* Riferisce al codice chiamante che abbiamo trattato l'evento; passa avanti. */
3903     return FALSE;
3904 }
3905
3906
3907 /* Stampa una stringa quando viene selezionato un elemento di men&ugrave; */
3908
3909 static void menuitem_response (gchar *string)
3910 {
3911     printf("%s\n", string);
3912 }
3913 </verb></tscreen>
3914
3915 Si pu&ograve; anche fare in modo che un elemento di men&ugrave; sia insensibile e, usando
3916 una tabella di acelleratori, collegare dei tasti a delle funzioni di men&ugrave;.
3917 <p>
3918 <sect1>Usare GtkMenuFactory
3919 <p>
3920 Ora che vi abbiamo mostrato il modo difficile, ecco invece come si fa usando
3921 le chiamate di gtk_menu_factory.
3922 <p>
3923 <sect1>Esempio di Menu Factory
3924 <p>
3925 Ecco un esempio di utilizzo della ``Fabbrica'' di Men&ugrave; di GTK (Menu Factory). 
3926 Questo &egrave; il primo file, menus.h. Teniemo dei file menus.c e main.c separati
3927 a causa delle variabili globali usate nel file menus.c.
3928
3929 <tscreen><verb>
3930 #ifndef __MENUS_H__
3931 #define __MENUS_H__
3932
3933 #ifdef __cplusplus
3934 extern "C" {
3935 #endif /* __cplusplus */
3936
3937 void get_main_menu (GtkWidget **menubar, GtkAcceleratorTable **table);
3938 void menus_create(GtkMenuEntry *entries, int nmenu_entries);
3939
3940 #ifdef __cplusplus
3941 }
3942 #endif /* __cplusplus */
3943
3944 #endif /* __MENUS_H__ */
3945 </verb></tscreen>
3946 <p>
3947 Ed ecco il file menus.c.
3948
3949 <tscreen><verb>
3950
3951 #include <gtk/gtk.h>
3952 #include <strings.h>
3953
3954 #include "main.h"
3955
3956
3957 static void menus_remove_accel(GtkWidget * widget, gchar * signal_name, gchar * path);
3958 static gint menus_install_accel(GtkWidget * widget, gchar * signal_name, gchar key, gchar modifiers, gchar * path);
3959 void menus_init(void);
3960 void menus_create(GtkMenuEntry * entries, int nmenu_entries);
3961
3962 /* Questa &egrave; la struttuta GtkMenuEntry, che viene usata per creare dei nuovi
3963  * men&ugrave;. Il primo membro &agrave; la stringa di definizione del men&ugrave;. Il secondo
3964  * &egrave; il tasto acceleratore predefinito, usato per accedere a questa funzione
3965  * con la tastiera. Il terzo &egrave; la funzione di ritorno che viene chiamata
3966  * quando si seleziona con la tastiera o il mouse questo elemento di men&ugrave;.
3967  * L'ultimo membro costituisce il dato che viene passato alla funzione di
3968  * ritorno. */
3969
3970 static GtkMenuEntry menu_items[] =
3971 {
3972         {"<Main>/File/New", "<control>N", NULL, NULL},
3973         {"<Main>/File/Open", "<control>O", NULL, NULL},
3974         {"<Main>/File/Save", "<control>S", NULL, NULL},
3975         {"<Main>/File/Save as", NULL, NULL, NULL},
3976         {"<Main>/File/<separator>", NULL, NULL, NULL},
3977         {"<Main>/File/Quit", "<control>Q", file_quit_cmd_callback, "OK, I'll quit"},
3978         {"<Main>/Options/Test", NULL, NULL, NULL}
3979 };
3980
3981 /* calculail numero di menu_item */
3982 static int nmenu_items = sizeof(menu_items) / sizeof(menu_items[0]);
3983
3984 static int initialize = TRUE;
3985 static GtkMenuFactory *factory = NULL;
3986 static GtkMenuFactory *subfactory[1];
3987 static GHashTable *entry_ht = NULL;
3988
3989 void get_main_menu(GtkWidget ** menubar, GtkAcceleratorTable ** table)
3990 {
3991     if (initialize)
3992             menus_init();
3993     
3994     if (menubar)
3995             *menubar = subfactory[0]->widget;
3996     if (table)
3997             *table = subfactory[0]->table;
3998 }
3999
4000 void menus_init(void)
4001 {
4002     if (initialize) {
4003         initialize = FALSE;
4004         
4005         factory = gtk_menu_factory_new(GTK_MENU_FACTORY_MENU_BAR);
4006         subfactory[0] = gtk_menu_factory_new(GTK_MENU_FACTORY_MENU_BAR);
4007         
4008         gtk_menu_factory_add_subfactory(factory, subfactory[0], "<Main>");
4009         menus_create(menu_items, nmenu_items);
4010     }
4011 }
4012
4013 void menus_create(GtkMenuEntry * entries, int nmenu_entries)
4014 {
4015     char *accelerator;
4016     int i;
4017     
4018     if (initialize)
4019             menus_init();
4020     
4021     if (entry_ht)
4022             for (i = 0; i < nmenu_entries; i++) {
4023                 accelerator = g_hash_table_lookup(entry_ht, entries[i].path);
4024                 if (accelerator) {
4025                     if (accelerator[0] == '\0')
4026                             entries[i].accelerator = NULL;
4027                     else
4028                             entries[i].accelerator = accelerator;
4029                 }
4030             }
4031     gtk_menu_factory_add_entries(factory, entries, nmenu_entries);
4032     
4033     for (i = 0; i < nmenu_entries; i++)
4034             if (entries[i].widget) {
4035                 gtk_signal_connect(GTK_OBJECT(entries[i].widget), "install_accelerator",
4036                                    (GtkSignalFunc) menus_install_accel,
4037                                    entries[i].path);
4038                 gtk_signal_connect(GTK_OBJECT(entries[i].widget), "remove_accelerator",
4039                                    (GtkSignalFunc) menus_remove_accel,
4040                                    entries[i].path);
4041             }
4042 }
4043
4044 static gint menus_install_accel(GtkWidget * widget, gchar * signal_name, gchar key, gchar modifiers, gchar * path)
4045 {
4046     char accel[64];
4047     char *t1, t2[2];
4048     
4049     accel[0] = '\0';
4050     if (modifiers & GDK_CONTROL_MASK)
4051             strcat(accel, "<control>");
4052     if (modifiers & GDK_SHIFT_MASK)
4053             strcat(accel, "<shift>");
4054     if (modifiers & GDK_MOD1_MASK)
4055             strcat(accel, "<alt>");
4056     
4057     t2[0] = key;
4058     t2[1] = '\0';
4059     strcat(accel, t2);
4060     
4061     if (entry_ht) {
4062         t1 = g_hash_table_lookup(entry_ht, path);
4063         g_free(t1);
4064     } else
4065             entry_ht = g_hash_table_new(g_string_hash, g_string_equal);
4066     
4067     g_hash_table_insert(entry_ht, path, g_strdup(accel));
4068     
4069     return TRUE;
4070 }
4071
4072 static void menus_remove_accel(GtkWidget * widget, gchar * signal_name, gchar * path)
4073 {
4074     char *t;
4075     
4076     if (entry_ht) {
4077         t = g_hash_table_lookup(entry_ht, path);
4078         g_free(t);
4079         
4080         g_hash_table_insert(entry_ht, path, g_strdup(""));
4081     }
4082 }
4083
4084 void menus_set_sensitive(char *path, int sensitive)
4085 {
4086     GtkMenuPath *menu_path;
4087     
4088     if (initialize)
4089             menus_init();
4090     
4091     menu_path = gtk_menu_factory_find(factory, path);
4092     if (menu_path)
4093             gtk_widget_set_sensitive(menu_path->widget, sensitive);
4094     else
4095             g_warning("Impossibile assegnare sensibilit&agrave; a men&ugrave; inesistente: %s", path);
4096 }
4097
4098 </verb></tscreen>
4099 <p>
4100 Ed ecco main.h
4101
4102 <tscreen><verb>
4103 #ifndef __MAIN_H__
4104 #define __MAIN_H__
4105
4106
4107 #ifdef __cplusplus
4108 extern "C" {
4109 #endif /* __cplusplus */
4110
4111 void file_quit_cmd_callback(GtkWidget *widget, gpointer data);
4112
4113 #ifdef __cplusplus
4114 }
4115 #endif /* __cplusplus */
4116
4117 #endif /* __MAIN_H__ */
4118
4119 </verb></tscreen>
4120 <p>
4121 E main.c
4122
4123 <tscreen><verb>
4124 #include <gtk/gtk.h>
4125
4126 #include "main.h"
4127 #include "menus.h"
4128
4129
4130 int main(int argc, char *argv[])
4131 {
4132     GtkWidget *window;
4133     GtkWidget *main_vbox;
4134     GtkWidget *menubar;
4135     
4136     GtkAcceleratorTable *accel;
4137     
4138     gtk_init(&amp;argc, &amp;argv);
4139     
4140     window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
4141     gtk_signal_connect(GTK_OBJECT(window), "destroy", 
4142                        GTK_SIGNAL_FUNC(file_quit_cmd_callback), 
4143                        "WM destroy");
4144     gtk_window_set_title(GTK_WINDOW(window), "Menu Factory");
4145     gtk_widget_set_usize(GTK_WIDGET(window), 300, 200);
4146     
4147     main_vbox = gtk_vbox_new(FALSE, 1);
4148     gtk_container_border_width(GTK_CONTAINER(main_vbox), 1);
4149     gtk_container_add(GTK_CONTAINER(window), main_vbox);
4150     gtk_widget_show(main_vbox);
4151     
4152     get_main_menu(&amp;menubar, &amp;accel);
4153     gtk_window_add_accelerator_table(GTK_WINDOW(window), accel);
4154     gtk_box_pack_start(GTK_BOX(main_vbox), menubar, FALSE, TRUE, 0);
4155     gtk_widget_show(menubar);
4156     
4157     gtk_widget_show(window);
4158     gtk_main();
4159     
4160     return(0);
4161 }
4162
4163 /* Questo &egrave; per mostrare come si usano le funzioni di ritorno quando 
4164  * si utilizza la MenuFactory. Spesso, si mettono tutte le funzioni di
4165  * callback in un file separato, e le si fanno chiamare le funzioni
4166  * appropriate da l&igrave;. Cos&igrave; le cose sono pi&ugrave; organizzate. */
4167 void file_quit_cmd_callback (GtkWidget *widget, gpointer data)
4168 {
4169     g_print ("%s\n", (char *) data);
4170     gtk_exit(0);
4171 }
4172 </verb></tscreen>
4173 <p>
4174 Ed infine un bel makefile per semplificare la compilazione.
4175
4176 <tscreen><verb>
4177 CC      = gcc
4178 PROF    = -g
4179 C_FLAGS =  -Wall $(PROF) -L/usr/local/include -DDEBUG
4180 L_FLAGS =  $(PROF) -L/usr/X11R6/lib -L/usr/local/lib 
4181 L_POSTFLAGS = -lgtk -lgdk -lglib -lXext -lX11 -lm
4182 PROGNAME = at
4183
4184 O_FILES = menus.o main.o
4185
4186 $(PROGNAME): $(O_FILES)
4187         rm -f $(PROGNAME)
4188         $(CC) $(L_FLAGS) -o $(PROGNAME) $(O_FILES) $(L_POSTFLAGS)
4189
4190 .c.o: 
4191         $(CC) -c $(C_FLAGS) $<
4192
4193 clean: 
4194         rm -f core *.o $(PROGNAME) nohup.out
4195 distclean: clean 
4196         rm -f *~
4197 </verb></tscreen>
4198 <p>
4199 Per il momento, accontentatevi di questo esempio. Pi&ugrave; avanti aggiungeremo
4200 una spiegazione ed un bel po' di commenti.
4201
4202
4203 <sect> Widget non documentati
4204 <p>
4205 Per questi sarebbe utile il contributo degli autori! :) Prendete in
4206 considerazione la possibilit&agrave; di contribuire al nostro tutorial.
4207
4208 Se dovete usare uno di questi widget non documentati, vi suggeriamo
4209 caldamente di dare un'occhiata ai loro rispettivi file header nella 
4210 distribuzione di GTK. I nomi delle funzioni di GTK sono molto descrittivi.
4211 Non appena si capisce come funzionano le cose, non &egrave; 
4212 difficile dedurre il modo d'uso di un widget semplicemente guardando la
4213 dichiarazione di funzione ad esso associata. Aggiungendo a questo qualche
4214 spunto tratto dal codice di altri non dovrebbero esserci problemi.
4215
4216 Quando avrete raggiunto una comprensione globale di tutte le funzioni
4217 di un widget non documentato, considerate la possibilit&agrave; di scrivere
4218 un tutorial su di esso, in modo che altri possano beneficiare del
4219 vostro lavoro.
4220
4221 <sect1> Ingressi di testo (Text Entries)
4222 <p>
4223
4224 <sect1> Selezioni di colore (Color Selections)
4225 <p>
4226
4227 <sect1> Controlli di intervallo (Range Controls)
4228 <p>
4229
4230 <sect1> Righelli (Rulers)
4231 <p>
4232
4233 <sect1> Caselle di testo (Text Boxes)
4234 <p>
4235
4236 <sect1> Anteprime
4237 <p>
4238
4239 (Potrebbe essere necessario riscrivere questa parte per conformarsi allo stile
4240 del resto del tutorial)
4241
4242 <p>
4243 Le anteprime servono a un certo numero di cose in GIMP/GTK. La pi&ugrave;
4244 importante &egrave; questa: a risoluzioni molto alte le immagini possono
4245 facilmente occupare diverse decine di megabyte di memoria; ogni operazione
4246 su immagini cos&igrave; grosse pu&ograve richiedere molto tempo. Se per la
4247 scelta di una data modifica vi occorrono 5-10 tentativi (cio&egrave; 10-20
4248 passi, poich&eacute; &egrave; necessario ripristinare l'originale se si 
4249 &egrave; commesso un errore), possono volerci letteralmente delle ore per
4250 fare quella giusta - se non si rimane a corto di memoria prima! Coloro che
4251 hanno passato ore in camera oscura conoscono la sensazione. In questi casi
4252 le anteprime sono utilissime!
4253
4254 Ma la seccatura dell'attesa non &egrave; l'unico caso. Spesso &egrave; utile
4255 confrontare la versione precedente con la successiva affiancandole, o almeno
4256 alternandole. Se si sta lavorando con grandi immagini e ritardi di una decina
4257 di secondi un confronto efficace &egrave; quantomeno difficile da fare.
4258 Per immagini di 30 mega (4 pollici per 6 pollici, 600 punti per pollice, 24 bit)
4259 tale confronto risulta impraticabile per la maggior parte degli utenti. In
4260 questo caso le anteprime sono di grande aiuto!  
4261
4262 Ma c'&egrave; di pi&ugrave;. Con le anteprime &egrave; possibile scrivere
4263 plug-in per ottenere addirittura anteprime di anteprime (per esempio, la
4264 simulazione del pacchetto di filtri). Questi plug-in possono cos&igrave;
4265 fornire un certo numero di anticipazioni di quel che si otterrebbe applicando
4266 certe opzioni. Un simile approccio funziona come una tavolozza di anteprime,
4267 ed &egrave; molto efficace per piccoli cambiamenti!  
4268
4269 Non &egrave; finita. Per alcuni plug-in pu&ograve; essere necessario un
4270 intervento umano in tempo reale specifico per ogni immagine. Nel plug-in 
4271 SuperNova, ad esempio, vengono chieste le coordinate del centro della
4272 futura supernova. Il modo pi&ugrave; semplice per fare questo &egrave;
4273 senza dubbio quello di mostrare un'anteprima all'utente chiedendogli di
4274 selezionare interattivamente il centro.
4275
4276 Infine, un paio di applicazioni tipiche. Le anteprime possono essere usate
4277 anche quando non si sta lavorando con grandi immagini. Per esempio, sono 
4278 utili quando si stanno calcolando dei pattern complicati (date un'occhiata
4279 al venerabile plug in ``Diffraction'' e a molti altri!). Altro esempio:
4280 date un'occhiata al plug-in di rotazione della mappa dei colori (in allestimento).
4281 Le anteprime possono anche essere usate per visualizzare in un plug-in
4282 piccoli logo o, addirittura, l'immagine dell'Autore!
4283
4284 Quando non usare le anteprime
4285
4286 Le anteprime non vanno usate per grafici, disegni ecc., poich&eacute; per 
4287 queste cose GDK &egrave; molto pi&ugrave; veloce. Le anteprime vanno usate
4288 solo per immagini derivate da un'elaborazione!
4289  
4290 Le anteprime possono essere inserite dappertutto. In un vbox, in un hbox,
4291 in una tabella, in un bottone, ecc. Sicuramente per&ograve; hanno il loro
4292 look migliore se bordate con delle cornici (frame). Le anteprime non hanno
4293 bordi propri e appaiono piatte senza (naturalmente, se quel che si vuole
4294 &egrave; proprio un aspetto piatto...). I bordi possono essere creati con
4295 delle cornici.
4296
4297                                [Image][Image]
4298
4299 Le anteprime sono per molti aspetti simili agli altri widget in GTK (con
4300 tutto ci&ograve; che questo implica), con l'eccezione di avere una
4301 caratteristica in pi&ugrave;: &egrave; necessario che siano riempite con
4302 qualche tipo di immagine! Inizialmente parleremo solo dell'aspetto GTK 
4303 delle anteprime e successivamente discuteremo di come riempirle.
4304
4305 Semplicemente:
4306
4307 <tscreen><verb>
4308                               /* Crea un widget di anteprima,
4309                                  inizializzane le dimensioni
4310                                  e visualizzalo */
4311 GtkWidget *preview;
4312 preview=gtk_preview_new(GTK_PREVIEW_COLOR)
4313                               /* Alternativamente:
4314                               GTK_PREVIEW_GRAYSCALE);*/
4315 gtk_preview_size (GTK_PREVIEW (preview), WIDTH, HEIGHT);
4316 gtk_widget_show(preview);
4317 my_preview_rendering_function(preview);
4318 </verb></tscreen>
4319
4320 Come gi&agrave; detto, le anteprime hanno un buon aspetto dentro le cornici,
4321 quindi:
4322
4323 <tscreen><verb>
4324 GtkWidget *create_a_preview(int        Width,
4325                             int        Height,
4326                             int        Colorfulness)
4327 {
4328   GtkWidget *preview;
4329   GtkWidget *frame;
4330   
4331   frame = gtk_frame_new(NULL);
4332   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
4333   gtk_container_border_width (GTK_CONTAINER(frame),0);
4334   gtk_widget_show(frame);
4335
4336   preview=gtk_preview_new (Colorfulness?GTK_PREVIEW_COLOR
4337                                        :GTK_PREVIEW_GRAYSCALE);
4338   gtk_preview_size (GTK_PREVIEW (preview), Width, Height);
4339   gtk_container_add(GTK_CONTAINER(frame),preview);
4340   gtk_widget_show(preview);
4341
4342   my_preview_rendering_function(preview);
4343   return frame;
4344 }
4345
4346 </verb></tscreen>
4347
4348 Questa &egrave; una semplice anteprima. Questa funzione restituisce la cornice
4349 ``madre'', in modo che sia possibile metterla in qualche altro posto nella vostra
4350 interfaccia. Naturalmente &egrave; possibile passare alla routine la cornice
4351 madre come parametro. In molte situazioni, comunque, il contenuto di un'anteprima
4352 viene aggiornato continuamente dall'applicazione; in questi casi potreste 
4353 preferire passare alla funzione ``create_a_preview()'' un puntatore 
4354 all'anteprima, ottenendone cos&igrave; il controllo dopo.
4355
4356 Un'avvertimento pi&ugrave; importante che potrebbe un giorno risparmiarvi 
4357 tanto tempo perso: a volte &egrave; preferibile etichettare le anteprime;
4358 ad esempio, &egrave; possibile etichettare l'anteprima contenente l'immagine 
4359 originale come ``Originale'' e quella contenente l'immagine modificata come 
4360 ``Modificata''. Potrebbe capitarvi di impacchettare in un vbox l'anteprima
4361 insieme con l'etichetta associata. L'insidia inattesa sta nel fatto che se
4362 l'etichetta &egrave; pi&ugrave; ampia dell'anteprima (cosa che pu&ograve;
4363 accadere per una variet&agrave; di motivi da voi non prevedibili, come il
4364 fatto che la dimensione dell'anteprima viene decisa dinamicamente, o la
4365 dimensione del font), la cornice si espande e non risulta pi&ugrave;
4366 perfettamente aderente all'anteprima. Questo stesso problema probabilmente
4367 pu&ograve; verificarsi anche in altre situazioni.
4368
4369                                    [Image]
4370
4371 La soluzione &egrave; quella di mettere l'anteprima e l'etichetta in una
4372 tabella 2x1 e di legarle insieme chiamando la funzione gtk_table_attach con
4373 i seguenti parametri (questa &egrave; una delle varianti possibili,
4374 naturalmente; l'importante &egrave; che non ci sia GTK_FILL nella seconda
4375 gtk_table_attach):
4376
4377 <tscreen><verb>
4378 gtk_table_attach(GTK_TABLE(table),label,0,1,0,1,
4379                  0,
4380                  GTK_EXPAND|GTK_FILL,
4381                  0,0);
4382 gtk_table_attach(GTK_TABLE(table),frame,0,1,1,2,
4383                  GTK_EXPAND,
4384                  GTK_EXPAND,
4385                  0,0);
4386 </verb></tscreen>
4387
4388 Ed ecco il risultato:
4389
4390                                    [Image]
4391
4392 Altri suggerimenti
4393
4394 La maniera pi&ugrave; semplice per rendere cliccabile un'anteprima &egrave; 
4395 quella di metterla dentro un bottone. Questo ha anche l'effetto di aggiungere 
4396 un bel bordo attorno all'anteprima, il che rende superfluo metterla in una 
4397 cornice.
4398
4399 Questo &egrave; tutto per quel che riguarda GTK.
4400
4401
4402 Completare un'anteprima
4403
4404 Per impratichirci con le basi del completamento delle anteprime, creiamo
4405 il seguente disegno (trovato per tentativi):
4406
4407                                    [Image]
4408
4409 <tscreen><verb>
4410 void
4411 my_preview_rendering_function(GtkWidget     *preview)
4412 {
4413 #define SIZE 100
4414 #define HALF (SIZE/2)
4415
4416   guchar *row=(guchar *) malloc(3*SIZE); /* 3 bits per dot */
4417   gint i, j;                             /* Coordinates    */
4418   double r, alpha, x, y;
4419
4420   if (preview==NULL) return; /* Di solito aggiungo questo per  */  
4421                              /* evitare piantamenti stupidi.   */
4422                              /* Probabilmente bisognerebbe     */
4423                              /* assicurarsi che tutto sia stato*/
4424                              /* inizializzato con successo     */
4425   for (j=0; j < ABS(cos(2*alpha)) ) {    /* Siamo dentro la sagoma?   */
4426                                          /* glib.h contiene ABS(x).   */
4427         row[i*3+0] = sqrt(1-r)*255;      /* Definisce il Rosso        */
4428         row[i*3+1] = 128;                /* Definisce il Verde        */
4429         row[i*3+2] = 224;                /* Definisce il Blu          */
4430       }                                  /* "+0" &egrave; per allineamento   */
4431       else {
4432         row[i*3+0] = r*255;
4433         row[i*3+1] = ABS(sin((float)i/SIZE*2*PI))*255;
4434         row[i*3+2] = ABS(sin((float)j/SIZE*2*PI))*255;
4435       }
4436     }
4437     gtk_preview_draw_row( GTK_PREVIEW(preview),row,0,j,SIZE);
4438     /* Inserisce "row" in "preview" a partire del punto avente */
4439     /* coordinate (0,j) prima colonna, j-esima riga, per SIZE  */
4440     /* pixel verso destra */
4441   }
4442
4443   free(row); /* libera un po' di memoria */
4444   gtk_widget_draw(preview,NULL); /* indovina cosa fa questo? */
4445   gdk_flush(); /* e questo? */
4446 }
4447 </verb></tscreen>
4448 Coloro che non usano GIMP probabilmente hanno gi&agrave; visto abbastanza
4449 per fare molte cose. Per gli utenti GIMP c'&egrave; ancora qualcosa da
4450 aggiungere.
4451  
4452 Anteprima dell'immagine
4453
4454 Probabilmente &egrave; opportuno tenere pronta una versione ridotta dell'immagine,
4455 grande quanto basta per riempire l'anteprima. Questo pu&ograve; essere fatto
4456 selezionando un pixel ogni n, dove n &egrave; il rapporto tra la dimensione
4457 dell'immagine e la dimensione dell'anteprima. Tutte le operazioni successive
4458 (compreso il riempimento dell'anteprima) sono fatte solo sul ridotto numero
4459 di pixel selezionati. Di seguito &egrave; riportata un'implementazione della
4460 riduzione dell'immagine (si tenga presente che ho preso solo lezioni basilari 
4461 di C!).
4462
4463
4464 (ATTENZIONE: CODICE NON VERIFICATO!!!)
4465
4466 <tscreen><verb>
4467
4468 typedef struct {
4469   gint      width;
4470   gint      height;
4471   gint      bbp;
4472   guchar    *rgb;
4473   guchar    *mask;
4474 } ReducedImage;
4475
4476 enum {
4477   SELECTION_ONLY,
4478   SELCTION_IN_CONTEXT,
4479   ENTIRE_IMAGE
4480 };
4481
4482 ReducedImage *Reduce_The_Image(GDrawable *drawable,
4483                                GDrawable *mask,
4484                                gint LongerSize,
4485                                gint Selection)
4486 {
4487   /* Questa funzione riduce l'immagine alla dimens. scelta per l'anteprima */
4488   /* La dimensione dell'anteprima &egrave; determinata da LongerSize, cio&egrave; la pi&ugrave; */
4489   /* grande delle dimensioni. Funziona solo per immagini RGB!              */
4490   gint RH, RW;          /* Altezza ridotta e larghezza ridotta             */
4491   gint width, height;   /* Larghezza e altezza dell'area da ridurre        */
4492   gint bytes=drawable->bpp;
4493   ReducedImage *temp=(ReducedImage *)malloc(sizeof(ReducedImage));
4494
4495   guchar *tempRGB, *src_row, *tempmask, *src_mask_row,R,G,B;
4496   gint i, j, whichcol, whichrow, x1, x2, y1, y2;
4497   GPixelRgn srcPR, srcMask;
4498   gint NoSelectionMade=TRUE; /* Assumiamo di trattare l'intera immagine    */                                         
4499
4500   gimp_drawable_mask_bounds (drawable->id, &amp;x1, &amp;y1, &amp;x2, &amp;y2);
4501   width  = x2-x1;
4502   height = y2-y1;
4503   /* Se c'&egrave; una SELEZIONE, ne abbiamo avuto gli estremi! */
4504
4505   if (width != drawable->width &amp;&amp; height != drawable->height)
4506     NoSelectionMade=FALSE;
4507   /* Controlliamo se l'utente ha una selezione attiva. Questo         */
4508   /* diventer&agrave; importante dopo, alla creazione di una maschera ridotta */
4509
4510   /* Se si vuole l'anteprima dell'immagine intera, annulla quanto sopra */
4511   /* Naturalmente, in assenza di una selezione, questo non cambia nulla */
4512   if (Selection==ENTIRE_IMAGE) {
4513     x1=0;
4514     x2=drawable->width;
4515     y1=0;
4516     y2=drawable->height;
4517   }
4518
4519   /* Se si vuole l'anteprima di una selezione con parte dell'area   */
4520   /* circostante bisogna espanderla un po'.                         */
4521   if (Selection==SELECTION_IN_CONTEXT) {
4522     x1=MAX(0,                x1-width/2.0);
4523     x2=MIN(drawable->width,  x2+width/2.0);
4524     y1=MAX(0,                y1-height/2.0);
4525     y2=MIN(drawable->height, y2+height/2.0);
4526   }
4527
4528   /* Cos&igrave; si determinano larghezza e altezza dell'area da ridurre.   */
4529   width  = x2-x1;
4530   height = y2-y1;
4531
4532   /* Le linee seguenti determinano quale dimensione deve essere  il  */
4533   /* lato pi&ugrave; lungo. L'idea &egrave; presa dal plug-in supernova. Ritengo   */
4534   /* che avrei potuto pensarci da solo, ma la verit&agrave; va detta.       */
4535   /* Brutta cosa il plagio!                                          */
4536   if (width>height) {
4537     RW=LongerSize;
4538     RH=(float) height * (float) LongerSize/ (float) width;
4539   }
4540   else {
4541     RH=LongerSize;
4542     RW=(float)width * (float) LongerSize/ (float) height;
4543   }
4544
4545   /* L'intera immagine viene "stirata" in una stringa! */
4546   tempRGB   = (guchar *) malloc(RW*RH*bytes);
4547   tempmask  = (guchar *) malloc(RW*RH);
4548
4549   gimp_pixel_rgn_init (&amp;srcPR, drawable, x1, y1, width, height, FALSE, FALSE);
4550   gimp_pixel_rgn_init (&amp;srcMask, mask, x1, y1, width, height, FALSE, FALSE);
4551
4552   /* Prendine abbastanza da contenere una riga di immagine e una di maschera */
4553   src_row       = (guchar *) malloc (width*bytes);
4554   src_mask_row  = (guchar *) malloc (width);
4555
4556   for (i=0; i < RH; i++) {
4557     whichrow=(float)i*(float)height/(float)RH;
4558     gimp_pixel_rgn_get_row (&amp;srcPR, src_row, x1, y1+whichrow, width);
4559     gimp_pixel_rgn_get_row (&amp;srcMask, src_mask_row, x1, y1+whichrow, width);
4560
4561     for (j=0; j < RW; j++) {
4562       whichcol=(float)j*(float)width/(float)RW;
4563
4564       /* Nessuna selezione = tutti i punti sono completamente selezionati */
4565       if (NoSelectionMade)
4566         tempmask[i*RW+j]=255;
4567       else
4568         tempmask[i*RW+j]=src_mask_row[whichcol];
4569
4570       /* Aggiungi la riga alla lunga stringa che ora contiene l'immagine */
4571       tempRGB[i*RW*bytes+j*bytes+0]=src_row[whichcol*bytes+0];
4572       tempRGB[i*RW*bytes+j*bytes+1]=src_row[whichcol*bytes+1];
4573       tempRGB[i*RW*bytes+j*bytes+2]=src_row[whichcol*bytes+2];
4574
4575       /* Mantieni anche la trasparenza (alpha) */
4576       if (bytes==4)
4577         tempRGB[i*RW*bytes+j*bytes+3]=src_row[whichcol*bytes+3];
4578     }
4579   }
4580   temp->bpp=bytes;
4581   temp->width=RW;
4582   temp->height=RH;
4583   temp->rgb=tempRGB;
4584   temp->mask=tempmask;
4585   return temp;
4586 }
4587 </verb></tscreen>
4588
4589
4590 La seguente &egrave; una funzione di anteprima che usa lo stesso tipo
4591 ReducedImage! Si noti che usa una finta trasparenza - se ne &egrave; presente 
4592 una, tramite fake_transparency che &egrave; definita come segue:
4593
4594 <tscreen><verb>
4595 gint fake_transparency(gint i, gint j)
4596 {
4597   if ( ((i%20)- 10) * ((j%20)- 10)>0   )
4598     return 64;
4599   else
4600     return 196;
4601 }
4602
4603 </verb></tscreen>
4604 E adesso la funzione per l'anteprima:
4605 <tscreen><verb>
4606 void
4607 my_preview_render_function(GtkWidget     *preview,
4608                            gint          changewhat,
4609                            gint          changewhich)
4610 {
4611   gint Inten, bytes=drawable->bpp;
4612   gint i, j, k;
4613   float partial;
4614   gint RW=reduced->width;
4615   gint RH=reduced->height;
4616   guchar *row=malloc(bytes*RW);;
4617
4618
4619   for (i=0; i < RH; i++) {
4620     for (j=0; j < RW; j++) {
4621
4622       row[j*3+0] = reduced->rgb[i*RW*bytes + j*bytes + 0];
4623       row[j*3+1] = reduced->rgb[i*RW*bytes + j*bytes + 1];
4624       row[j*3+2] = reduced->rgb[i*RW*bytes + j*bytes + 2];
4625
4626       if (bytes==4)
4627         for (k=0; k<3; k++) {
4628           float transp=reduced->rgb[i*RW*bytes+j*bytes+3]/255.0;
4629           row[3*j+k]=transp*a[3*j+k]+(1-transp)*fake_transparency(i,j);
4630         }
4631     }
4632     gtk_preview_draw_row( GTK_PREVIEW(preview),row,0,i,RW);
4633   }
4634
4635   free(a);
4636   gtk_widget_draw(preview,NULL);
4637   gdk_flush();
4638 }
4639
4640 Funzioni Applicabili
4641
4642 guint           gtk_preview_get_type           (void);
4643 /* No idea */
4644 void            gtk_preview_uninit             (void);
4645 /* No idea */
4646 GtkWidget*      gtk_preview_new                (GtkPreviewType   type);
4647 /* Descritta precedentemente */
4648 void            gtk_preview_size               (GtkPreview      *preview,
4649                                                 gint             width,
4650                                                 gint             height);
4651 /* Permette di ridimensionare un'anteprima esistente */
4652 /* Pare che un bug in GTK renda disordinato questo   */
4653 /* processo. Un modo di rimettere le cose a posto    */
4654 /* &egrave; quello di ridimensionare manualmente            */
4655 /* la finestra contenente l'anteprima dopo aver      */
4656 /* ridimensionato l'anteprima.                       */
4657
4658 void            gtk_preview_put                (GtkPreview      *preview,
4659                                                 GdkWindow       *window,
4660                                                 GdkGC           *gc,
4661                                                 gint             srcx,
4662                                                 gint             srcy,
4663                                                 gint             destx,
4664                                                 gint             desty,
4665                                                 gint             width,
4666                                                 gint             height);
4667 /* No idea */
4668
4669 void            gtk_preview_put_row            (GtkPreview      *preview,
4670                                                 guchar          *src,
4671                                                 guchar          *dest,
4672                                                 gint             x,
4673                                                 gint             y,
4674                                                 gint             w);
4675 /* No idea */
4676
4677 void            gtk_preview_draw_row           (GtkPreview      *preview,
4678                                                 guchar          *data,
4679                                                 gint             x,
4680                                                 gint             y,
4681                                                 gint             w);
4682 /* Descritta nel testo */
4683
4684 void            gtk_preview_set_expand         (GtkPreview      *preview,
4685                                                 gint             expand);
4686 /* No idea */
4687
4688 /* Nessun indizio per le seguenti, ma  dovrebbero  */
4689 /* essere standard per la maggior parte dei widget */
4690 void            gtk_preview_set_gamma          (double           gamma);
4691 void            gtk_preview_set_color_cube     (guint            nred_shades,
4692                                                 guint            ngreen_shades,
4693                                                 guint            nblue_shades,
4694                                                 guint            ngray_shades);
4695 void            gtk_preview_set_install_cmap   (gint             install_cmap);
4696 void            gtk_preview_set_reserved       (gint             nreserved);
4697 GdkVisual*      gtk_preview_get_visual         (void);
4698 GdkColormap*    gtk_preview_get_cmap           (void);
4699 GtkPreviewInfo* gtk_preview_get_info           (void);
4700
4701 E' tutto!
4702
4703 </verb></tscreen>
4704
4705
4706 <sect1> Curve
4707 <p>
4708
4709
4710 <sect>Il Widget EventBox<label id="sec_The_EventBox_Widget">
4711 <p>
4712 E' disponibile solo a partire dalla distribuzione gtk+970916.tar.gz.
4713 <p> 
4714 Alcuni widget gtk non sono associati a finestre X, sicch&eacute;
4715 semplicemente disegnano sui loro genitori. Per questo motivo essi non possono 
4716 ricevere eventi e se sono sovradimensionati non vengono troncati, ma rischiano
4717 di sovrapporsi, generando confusione. Se si vuole di pi&ugrave; da questi 
4718 widget si pu&ograve; ricorrere agli EventBox.
4719
4720 A prima vista il widget EventBox potrebbe sembrare completamente inutile. Non 
4721 disegna nulla sullo schermo e non risponde a nessun evento. Tuttavia ha 
4722 una funzione: fornire una finestra X al suo widget figlio. Ci&ograve;
4723 &egrave; importante in quanto molti widget GTK non hanno una finestra X
4724 associata. Se questo da una parte risparmia memoria e migliora le prestazioni,
4725 dall'altra introduce degli svantaggi: un widget senza una finestra X non 
4726 pu&ograve; ricevere eventi, e non taglia in alcun modo il suo contenuto.
4727 Sebbene il nome ``EventBox'' (casella di eventi) enfasizzi la funzione di 
4728 gestione degli eventi, il widget pu&ograve; essere usato anche per 
4729 limitare la dimensione dei widget figli (ma anche per altro: si veda 
4730 l'esempio seguente).
4731
4732 <p>
4733 Per creare un widget di tipo EventBox:
4734
4735 <tscreen><verb>
4736 GtkWidget* gtk_event_box_new (void);
4737 </verb></tscreen>
4738
4739 <p>
4740 All'EventBox si pu&ograve aggiungere un widget figlio:
4741
4742 <tscreen><verb>
4743 gtk_container_add (GTK_CONTAINER(event_box), widget);
4744 </verb></tscreen>
4745
4746 <p>
4747 The following example demonstrates both uses of an EventBox - a label
4748 is created that clipped to a small box, and set up so that a
4749 mouse-click on the label causes the program to exit.
4750 Il seguente esempio mostra entrambi gli usi di un EventBox - si crea 
4751 un'etichetta limitata da un rettangolo piccolo, fatta in modo che
4752 cliccando con il mouse su di essa il programma termina.
4753
4754 <tscreen><verb>
4755 #include <gtk/gtk.h>
4756
4757 int 
4758 main (int argc, char *argv[])
4759 {
4760     GtkWidget *window;
4761     GtkWidget *event_box;
4762     GtkWidget *label;
4763     
4764     gtk_init (&amp;argc, &amp;argv);
4765     
4766     window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
4767     
4768     gtk_window_set_title (GTK_WINDOW (window), "Event Box");
4769     
4770     gtk_signal_connect (GTK_OBJECT (window), "destroy",
4771                         GTK_SIGNAL_FUNC (gtk_exit), NULL);
4772     
4773     gtk_container_border_width (GTK_CONTAINER (window), 10);
4774     
4775     /* Crea un EventBox e lo aggiunge alla finestra principale */
4776
4777     event_box = gtk_event_box_new ();
4778     gtk_container_add (GTK_CONTAINER(window), event_box);
4779     gtk_widget_show (event_box);
4780     
4781     /* Crea una etichetta lunga */
4782     
4783     label = gtk_label_new ("Click here to quit, quit, quit, quit, quit");
4784     gtk_container_add (GTK_CONTAINER (event_box), label);
4785     gtk_widget_show (label);
4786     
4787     /* Limitane le dimensioni */
4788     gtk_widget_set_usize (label, 110, 20);
4789     
4790     /* E collega ad essa una azione */
4791     gtk_widget_set_events (event_box, GDK_BUTTON_PRESS_MASK);
4792     gtk_signal_connect (GTK_OBJECT(event_box), "button_press_event",
4793                         GTK_SIGNAL_FUNC (gtk_exit), NULL);
4794     
4795     /* Un'altra cosa per cui si ha bisogno di una finestra X ... */
4796     
4797     gtk_widget_realize (event_box);
4798     gdk_window_set_cursor (event_box->window, gdk_cursor_new (GDK_HAND1));
4799     
4800     gtk_widget_show (window);
4801     
4802     gtk_main ();
4803     
4804     return 0;
4805 }
4806 </verb></tscreen>
4807
4808 <sect>Selezionare gli Attributi dei Widget<label id="sec_setting_widget_attributes">
4809 <p>
4810 Qui si descrivono le funzioni per la gestione dei widget. Esse possono essere 
4811 usate per impostarne lo stile, il padding, le dimensioni, ...
4812
4813 (Forse andrebbe fatta un'intera sezione sugli acceleratori).
4814
4815 <tscreen><verb>
4816 void       gtk_widget_install_accelerator (GtkWidget           *widget,
4817                                            GtkAcceleratorTable *table,
4818                                            gchar               *signal_name,
4819                                            gchar                key,
4820                                            guint8               modifiers);
4821
4822 void       gtk_widget_remove_accelerator  (GtkWidget           *widget,
4823                                            GtkAcceleratorTable *table,
4824                                            gchar               *signal_name);
4825
4826 void       gtk_widget_activate            (GtkWidget           *widget);
4827
4828 void       gtk_widget_set_name            (GtkWidget           *widget,
4829                                            gchar               *name);
4830 gchar*     gtk_widget_get_name            (GtkWidget           *widget);
4831
4832 void       gtk_widget_set_sensitive       (GtkWidget           *widget,
4833                                            gint                 sensitive);
4834
4835 void       gtk_widget_set_style           (GtkWidget           *widget,
4836                                            GtkStyle            *style);
4837                                            
4838 GtkStyle*    gtk_widget_get_style     (GtkWidget *widget);
4839
4840 GtkStyle*    gtk_widget_get_default_style    (void);
4841
4842 void       gtk_widget_set_uposition       (GtkWidget           *widget,
4843                                            gint                 x,
4844                                            gint                 y);
4845 void       gtk_widget_set_usize           (GtkWidget           *widget,
4846                                            gint                 width,
4847                                            gint                 height);
4848
4849 void       gtk_widget_grab_focus          (GtkWidget           *widget);
4850
4851 void       gtk_widget_show                (GtkWidget           *widget);
4852
4853 void       gtk_widget_hide                (GtkWidget           *widget);
4854 </verb></tscreen>
4855
4856
4857
4858 <sect>Funzioni periodiche, di I/O e di attesa<label id="sec_timeouts">
4859 <p>
4860 <sect1>Funzioni periodiche
4861 <p>
4862 Probabilmente vi sarete chiesti come far fare qualcosa di utile a GTK
4863 durante la chiamata alla gtk_main(). Ci sono diverse possibilit&agrave;.
4864 Usando le seguenti funzioni si possono creare funzioni che vengono chiamate
4865 periodicamente.
4866
4867 <tscreen><verb>
4868 gint gtk_timeout_add (guint32 interval,
4869                       GtkFunction function,
4870                       gpointer data);
4871 </verb></tscreen>
4872
4873 Il primo argomento &egrave; il numero di millisecondi tra le chiamate alla 
4874 funzione. Il secondo &egrave; la funzione periodica, mentre il terzo
4875 rappresenta i dati che vengono passati alla funzione. Il valore restituito
4876 &egrave; un'etichetta che pu&ograve; essere utilizzata per fermare la chiamata
4877 periodica, passandolo alla funzione:
4878
4879 <tscreen><verb>
4880 void gtk_timeout_remove (gint tag);
4881 </verb></tscreen>
4882
4883 La chiamata periodica si ferma anche se la funzione periodica ritorna zero
4884 o FALSE. Naturalmente questo vuol dire che se si vuole che la funzione periodica
4885 continui ad essere richiamata, essa deve restituire un valore non nullo,
4886 cio&egrave; TRUE.
4887
4888 La dichiarazione della funzione periodica dovrebbe essere come questa:
4889
4890 <tscreen><verb>
4891 gint timeout_callback (gpointer data);
4892 </verb></tscreen>
4893
4894 <sect1>Controllo dell'I/O
4895 <p>
4896 Un'altra utile caratteristica di GTK &egrave; la possibilit&agrave; di fargli
4897 controllare che siano verificate certe condizioni su un descrittore di file 
4898 (come quelli restituiti da open(2) o socket(2)). Questo &egrave; utile in
4899 particolar modo per le applicazioni di rete. La funzione &egrave; la seguente:
4900
4901 <tscreen><verb>
4902 gint gdk_input_add (gint source,
4903                     GdkInputCondition condition,
4904                     GdkInputFunction  function,
4905                     gpointer data);
4906 </verb></tscreen>
4907
4908 Il primo argomento &egrave; il descrittore che si desidera venga controllato,
4909 mentre il secondo specifica quale condizione si vuole che GDK controlli.
4910 Questa pu&ograve; essere una tra:
4911 <p>
4912 GDK_INPUT_READ - Chiama la funzione quando ci sono dati pronti per la lettura
4913 nel descrittore di file.
4914 <p>
4915 GDK_INPUT_WRITE - Chiama la funzione quando il descrittore di file &egrave; 
4916 pronto per la scrittura.
4917 <p>
4918 Come sicuramente avrete gi&agrave; intuito, il terzo parametro &egrave; la
4919 funzione da chiamare quando la condizione specificata &egrave; soddisfatta,
4920 mentre il quarto rappresenta i dati da passare a questa funzione.
4921 <p>
4922 Il valore di ritorno  &egrave; un etichetta che pu&ograve; essere usata per
4923 fermare il controllo di GDK sul descrittore di file, usando la seguente
4924 funzione:
4925 <p>
4926 <tscreen><verb>
4927 void gdk_input_remove (gint tag);
4928 </verb></tscreen>
4929 <p>
4930 La funzione da richiamare va dichiarata cos&igrave;:
4931 <p>
4932 <tscreen><verb>
4933 void input_callback (gpointer data, gint source, 
4934                      GdkInputCondition condition);
4935 </verb></tscreen>
4936 <p>
4937
4938 <sect1>Funzioni di attesa (``Idle'')
4939 <p>
4940 Cosa fare se si ha una funzione che si vuole venga chiamata quando non
4941 sta accadendo nient'altro?
4942
4943 <tscreen><verb>
4944 gint gtk_idle_add (GtkFunction function,
4945                    gpointer data);
4946 </verb></tscreen>
4947
4948 Questa fa si che GDK chiami la funzione specificata quando non c'&egrave;
4949 nessuna altra operazione in corso.
4950
4951 <tscreen><verb>
4952 void gtk_idle_remove (gint tag);
4953 </verb></tscreen>
4954 <p>
4955 Non ci soffermeremo sul significato dei parametri in quanto del tutto analoghi
4956 ai precedenti. La funzione puntata dal primo argomento della gtk_idle_add 
4957 viene chiamata non appena se ne presenta l'opportunit&agrave;; come 
4958 negli altri casi, se essa restituisce FALSE non viene pi&ugrave; chiamata.
4959
4960
4961 <sect>La gestione delle selezioni
4962
4963 <sect1> Overview
4964
4965 <p>
4966
4967 Le <em>selezioni</em> sono un tipo di comunicazione tra processi
4968 supportato da GTK. Una selezione identifica un frammento di dati; per 
4969 esempio, una porzione di testo selezionata dall'utente in qualche modo,
4970 magari con il mouse. Su un display solo un'applicazione alla volta
4971 (il <em>proprietario</em>) pu&oacute; essere proprietaria di una
4972 particolare selezione, sicch&eacute; quando un'applicazione richiede
4973 una selezione il precedente proprietario deve comunicare all'utente che
4974 la selezione &egrave; stata ceduta. Altre applicazioni possono richiedere
4975 il contenuto di una selezione in diverse forme, chiamate <em>obiettivi</em>.
4976 Ci pu&ograve; essere un numero qualsiasi di selezioni, ma la maggior parte
4977 delle applicazioni X pu&ograve; gestirne solo una, la <em>selezione
4978 primaria</em>.
4979
4980 <p>
4981 Nella maggior parte dei casi per una applicazione GTK non &egrave; 
4982 necessario gestire esplicitamente le selezioni. I widget standard,
4983 come quello di Ingresso, hanno gi&agrave; la capacit&agrave; di
4984 chiedere la selezione se necessario (p. e., quando l'utente
4985 seleziona sul testo), e di recuperare il contenuto di una selezione
4986 di un altro widget o di un'altra applicazione (p. e., quando l'utente
4987 clicca il tasto centrale del mouse). Ci possono comunque essere dei
4988 casi nei quali si vuole dare ad altri widget la capacit&agrave; di
4989 fornire la selezione, o si vogliono recuperare degli obiettivi non
4990 supportati direttamente.
4991
4992 <p>
4993 Un concetto fondamentale necessario per comprendere la gestione delle
4994 selezioni &egrave; quello di <em>atomo</em>. Un atomo &egrave; un intero
4995 che identifica univocamente una stringa (su un certo display).
4996 Certi atomi sono predefiniti dal server X, e in alcuni casi in <tt>gtk.h</tt>
4997 ci sono costanti corrispondenti a questi atomi. Per esempio, la costante
4998 <tt>GDK_PRIMARY_SELECTION</tt> corrisponde alla stringa ``PRIMARY''.
4999 Negli altri casi bisogna usare le funzioni <tt>gdk_atom_intern()</tt>
5000 per ottenere l'atomo corrispondente ad una stringa, e <tt>gdk_atom_name()</tt>
5001 per ottenere il nome di un atomo. Sia le selezioni sia gli obiettivi sono
5002 identificati da atomi.
5003
5004 <sect1> Recuperare le selezioni
5005
5006 <p>
5007
5008 Il recupero di una selezione &egrave;  un processo asincrono. Per iniziare 
5009 il processo, si chiama:
5010 <tscreen><verb>
5011 gint gtk_selection_convert   (GtkWidget           *widget, 
5012                               GdkAtom              selection, 
5013                               GdkAtom              target,
5014                               guint32              time)
5015 </verb</tscreen>
5016
5017 Questo <em>converte</em> la selezione nella forma specificata 
5018 dall'obiettivo <tt/target/. Se possibile, il campo <tt/time/ 
5019 dovrebbe essere il tempo dell'evento che ha attivato la selezione.
5020 Questo aiuta a far si che gli eventi avvengano nell'ordine in cui
5021 l'utente li ha richiesti. Se comunque non fosse disponibile (per
5022 esempio, se la conversione &egrave; stata attivata da un segnale di
5023 ``cliccato''), allora si pu&ograve; usare la costante 
5024 <tt>GDK_CURRENT_TIME</tt>.
5025
5026 <p>
5027 Quando il proprietario di una selezione risponde ad una richiesta,
5028 un segnale ``selection_received'' (selezione ricevuta) viene inviato
5029 alla vostra applicazione. Il gestore di questo segnale riceve un 
5030 puntatore ad una struttura <tt>GtkSelectionData</tt>, che &egrave;
5031 definita nel modo seguente:
5032 <tscreen><verb>
5033 struct _GtkSelectionData
5034 {
5035   GdkAtom selection;
5036   GdkAtom target;
5037   GdkAtom type;
5038   gint    format;
5039   guchar *data;
5040   gint    length;
5041 };
5042 </verb></tscreen>
5043 <tt>selection</tt> e <tt>target</tt> sono i valori da voi specificati
5044 nella chiamata <tt>gtk_selection_convert()</tt>. <tt>type</tt> &egrave;
5045 un atomo che identifica il tipo di dati restituiti dal proprietario della
5046 selezione. Alcuni valori possibili sono ``STRING'', una stringa di 
5047 caratteri latin-1, ``ATOM'', una serie di atomi, ``INTEGER'', un intero, ecc. 
5048 La maggior parte degli obiettivi pu&ograve; restituire solo un tipo.
5049 <tt/format/ ci d&agrave; la lunghezza delle unit&agrave; (per esempio caratteri)
5050 in bit. Di solito, quando si ricevono i dati non ci si cura di questo.
5051 <tt>data</tt> &egrave; un puntatore ai dati restituiti, e <tt>length</tt>
5052 &egrave; la lunghezza dei dati restituiti, in byte. Se <tt>length</tt>
5053 &egrave; negativo allora si &egrave; verificato un errore e non &egrave;
5054 stato possibile recuperare la selezione. Questo pu&ograve; avvenire se
5055 nessuna applicazione era proprietaria della selezione, o se si &egrave;
5056 richiesto un obiettivo non supportato dall'applicazione. Viene garantito
5057 che il buffer sia un byte pi&ugrave; lungo di <tt>length</tt>; il byte
5058 in pi&ugrave; sar&agrave; sempre zero, in modo che non sia necessario
5059 ricopiare le stringhe solo per farle terminare con zero.
5060
5061 <p>
5062 Nell'esempio che segue viene recuperato l'obiettivo speciale ``TARGETS'',
5063 che &egrave; una lista di tutti gli obiettivi in cui pu&ograve; essere
5064 convertita la selezione.
5065 <tscreen><verb>
5066 #include <gtk/gtk.h>
5067
5068 void selection_received (GtkWidget *widget, 
5069                          GtkSelectionData *selection_data, 
5070                          gpointer data);
5071
5072 /* Gestore di segnale chiamato quando l'utente clicca nel bottone */
5073 /* "Get Targets"                                                   */
5074 void
5075 get_targets (GtkWidget *widget, gpointer data)
5076 {
5077   static GdkAtom targets_atom = GDK_NONE;
5078
5079   /* Prende l'atomo corrispondente alla stringa "TARGETS" */
5080   if (targets_atom == GDK_NONE)
5081     targets_atom = gdk_atom_intern ("TARGETS", FALSE);
5082
5083   /* E richiede l'obiettivo "TARGETS" per la selezione primaria */
5084   gtk_selection_convert (widget, GDK_SELECTION_PRIMARY, targets_atom,
5085                          GDK_CURRENT_TIME);
5086 }
5087
5088 /* Gestore di segnale chiamato quando il proprietario della selezione */
5089 /* restituisce i dati                                                 */
5090 void
5091 selection_received (GtkWidget *widget, GtkSelectionData *selection_data, 
5092                     gpointer data)
5093 {
5094   GdkAtom *atoms;
5095   GList *item_list;
5096   int i;
5097
5098   /* **** IMPORTANTE **** Controlla che il recupero sia riuscito */
5099   if (selection_data->length < 0)
5100     {
5101       g_print ("Selection retrieval failed\n");
5102       return;
5103     }
5104   /* Make sure we got the data in the expected form */
5105   if (selection_data->type != GDK_SELECTION_TYPE_ATOM)
5106     {
5107       g_print ("Selection \"TARGETS\" was not returned as atoms!\n");
5108       return;
5109     }
5110   
5111   /* Stampa gli atomi ricevuti */
5112   atoms = (GdkAtom *)selection_data->data;
5113
5114   item_list = NULL;
5115   for (i=0; i<selection_data->length/sizeof(GdkAtom); i++)
5116     {
5117       char *name;
5118       name = gdk_atom_name (atoms[i]);
5119       if (name != NULL)
5120         g_print ("%s\n",name);
5121       else
5122         g_print ("(bad atom)\n");
5123     }
5124
5125   return;
5126 }
5127
5128 int 
5129 main (int argc, char *argv[])
5130 {
5131   GtkWidget *window;
5132   GtkWidget *button;
5133   
5134   gtk_init (&amp;argc, &amp;argv);
5135
5136   /* Create the toplevel window */
5137
5138   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
5139   gtk_window_set_title (GTK_WINDOW (window), "Event Box");
5140   gtk_container_border_width (GTK_CONTAINER (window), 10);
5141
5142   gtk_signal_connect (GTK_OBJECT (window), "destroy",
5143                       GTK_SIGNAL_FUNC (gtk_exit), NULL);
5144
5145   /* Crea un bottone che l'utente pu&ograve; cliccare per ottenere gli obiettivi */
5146
5147   button = gtk_button_new_with_label ("Get Targets");
5148   gtk_container_add (GTK_CONTAINER (window), button);
5149
5150   gtk_signal_connect (GTK_OBJECT(button), "clicked",
5151                       GTK_SIGNAL_FUNC (get_targets), NULL);
5152   gtk_signal_connect (GTK_OBJECT(button), "selection_received",
5153                       GTK_SIGNAL_FUNC (selection_received), NULL);
5154
5155   gtk_widget_show (button);
5156   gtk_widget_show (window);
5157   
5158   gtk_main ();
5159   
5160   return 0;
5161 }
5162 </verb></tscreen>
5163
5164 <sect1> Fornire una selezione 
5165
5166 <p>
5167 Fornire la selezione &egrave; un po' pi&ugrave; complicato. Bisogna
5168 registrare i gestori che verranno chiamati quando viene richiesta la
5169 propria selezione. Per ogni coppia selezione/obiettivo che si gestir&agrave;
5170 occorre una chiamata a:
5171
5172 <tscreen><verb>
5173 void gtk_selection_add_handler (GtkWidget           *widget, 
5174                                 GdkAtom              selection,
5175                                 GdkAtom              target,
5176                                 GtkSelectionFunction function,
5177                                 GtkRemoveFunction    remove_func,
5178                                 gpointer             data);
5179 </verb></tscreen>
5180
5181 <tt/widget/, <tt/selection/, e <tt/target/ identificano le richieste
5182 che questo gestore soddisfer&agrave;.  <tt/remove_func/, se non &egrave;
5183 NULL, verr&agrave; chiamato quando il gestore di segnale viene rimosso.
5184 Questo &egrave; utile, per esempio, per linguaggi interpretati ai quali
5185 serve di tener traccia di un conteggio di riferimento per <tt/data/.
5186
5187 <p>
5188 La funzione di richiamo ha la forma:
5189
5190 <tscreen><verb>
5191 typedef void (*GtkSelectionFunction) (GtkWidget *widget, 
5192                                       GtkSelectionData *selection_data,
5193                                       gpointer data);
5194
5195 </verb></tscreen>
5196
5197 La GtkSelectionData &egrave; la stessa di prima, ma stavolta siamo
5198 responsabili di riempire i campi <tt/type/, <tt/format/, <tt/data/,
5199 e <tt/length/. (Il campo <tt/format/ qui &egrave; effettivamente 
5200 importante - il server  X lo usa per capire se occorre che i byte
5201 dei dati vengano scambiati o no. Di solito sar&agrave; 8 - cio&egrave;
5202 un carattere - o 32 - cio&egrave; un intero.) Questo viene fatto
5203 chiamando la funzione:
5204
5205 <tscreen><verb>
5206 void gtk_selection_data_set (GtkSelectionData *selection_data,
5207                              GdkAtom           type,
5208                              gint              format,
5209                              guchar           *data,
5210                              gint              length);
5211 </verb></tscreen>
5212 Questa funzione si prende cura di fare propriamente una copia dei dati
5213 in modo che non ci si debba preoccupare di conservarli (&egrave; opportuno
5214 evitare di riempire a mano i campi della struttura GtkSelectionData).
5215
5216 <p>
5217 Quando richiesto dall'utente, richiederete la propriet&agrave; della selezione
5218 chiamando:
5219
5220 <tscreen><verb>
5221 gint gtk_selection_owner_set (GtkWidget           *widget,
5222                               GdkAtom              selection,
5223                               guint32              time);
5224 </verb></tscreen>
5225
5226 Se un'altra applicazione richiede la propriet&agrave; della selezione,
5227 riceverete un evento di azzeramento della selezione (``selection_clear_event'').
5228
5229 Come esempio di fornitura della selezione, il programma seguente aggiunge
5230 la funzionalit&agrave; di selezione a un bottone di attivazione. Quando il
5231 bottone viene premuto, il programma richiede la selezione primaria.
5232 L'unico obiettivo supportato (oltre a certi obiettivi come ``TARGETS''
5233 fornito dalla stessa GTK) &egrave; l'obiettivo ``STRING''. Quando viene
5234 richiesto questo obiettivo, viene restituita una rappresentazione stringa
5235 del tempo.
5236
5237 <tscreen><verb>
5238 #include <gtk/gtk.h>
5239 #include <time.h>
5240
5241 /* Richiamata quando l'utente attiva la selezione */ 
5242 void
5243 selection_toggled (GtkWidget *widget, gint *have_selection)
5244 {
5245   if (GTK_TOGGLE_BUTTON(widget)->active)
5246     {
5247       *have_selection = gtk_selection_owner_set (widget,
5248                                                  GDK_SELECTION_PRIMARY,
5249                                                  GDK_CURRENT_TIME);
5250       /* se il richiamo della selezione &egrave; fallito, si riporta il
5251          bottone nello stato non premuto */
5252       if (!*have_selection)
5253         gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON(widget), FALSE);
5254     }
5255   else
5256     {
5257       if (*have_selection)
5258         {
5259           /* Prima di annullare la selezione mettendone a NULL il proprietario,
5260              controlliamo se siamo i veri proprietari */
5261           if (gdk_selection_owner_get (GDK_SELECTION_PRIMARY) == widget->window)
5262             gtk_selection_owner_set (NULL, GDK_SELECTION_PRIMARY,
5263                                      GDK_CURRENT_TIME);
5264           *have_selection = FALSE;
5265         }
5266     }
5267 }
5268
5269 /* Chiamata quando un'altra applicazione richiede la selezione */
5270 gint
5271 selection_clear (GtkWidget *widget, GdkEventSelection *event,
5272                  gint *have_selection)
5273 {
5274   *have_selection = FALSE;
5275   gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON(widget), FALSE);
5276
5277   return TRUE;
5278 }
5279
5280 /* Fornisce come selezione il tempo attuale */
5281 void
5282 selection_handle (GtkWidget *widget, 
5283                   GtkSelectionData *selection_data,
5284                   gpointer data)
5285 {
5286   gchar *timestr;
5287   time_t current_time;
5288
5289   current_time = time (NULL);
5290   timestr = asctime (localtime(&amp;current_time)); 
5291   /* Quando si restituisce una singola stringa, non occorre che finisca
5292      con NULL. Questo verr&agrave; fatto automaticamente */
5293      
5294   gtk_selection_data_set (selection_data, GDK_SELECTION_TYPE_STRING,
5295                           8, timestr, strlen(timestr));
5296 }
5297
5298 int
5299 main (int argc, char *argv[])
5300 {
5301   GtkWidget *window;
5302
5303   GtkWidget *selection_button;
5304
5305   static int have_selection = FALSE;
5306   
5307   gtk_init (&amp;argc, &amp;argv);
5308
5309   /* Crea la finestra di livello superiore */
5310
5311   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
5312   gtk_window_set_title (GTK_WINDOW (window), "Event Box");
5313   gtk_container_border_width (GTK_CONTAINER (window), 10);
5314
5315   gtk_signal_connect (GTK_OBJECT (window), "destroy",
5316                       GTK_SIGNAL_FUNC (gtk_exit), NULL);
5317
5318   /* Crea un bottone a commutazione che agisce come la selezione */
5319
5320   selection_button = gtk_toggle_button_new_with_label ("Claim Selection");
5321   gtk_container_add (GTK_CONTAINER (window), selection_button);
5322   gtk_widget_show (selection_button);
5323
5324   gtk_signal_connect (GTK_OBJECT(selection_button), "toggled",
5325                       GTK_SIGNAL_FUNC (selection_toggled), &amp;have_selection);
5326   gtk_signal_connect (GTK_OBJECT(selection_button), "selection_clear_event",
5327                       GTK_SIGNAL_FUNC (selection_clear), &amp;have_selection);
5328
5329   gtk_selection_add_handler (selection_button, GDK_SELECTION_PRIMARY,
5330                              GDK_SELECTION_TYPE_STRING,
5331                              selection_handle, NULL, NULL);
5332
5333   gtk_widget_show (selection_button);
5334   gtk_widget_show (window);
5335   
5336   gtk_main ();
5337   
5338   return 0;
5339 }
5340 </verb></tscreen>
5341
5342
5343
5344 <sect>La glib<label id="sec_glib">
5345 <p>
5346 La glib fornisce molte funzioni e definizioni utili pronte all'uso quando si
5347 creano applicazioni GDK e GTK. Qui verranno elencate tutte, con una
5348 breve spiegazione. Molte sono duplicati delle funzioni standard della libc,
5349 e quindi per queste non si scender&agrave; nei dettagli. Questa vuole essere una
5350 lista di riferimento, in modo che si sappia cosa &egrave; possibile usare.
5351
5352 <sect1>Definizioni
5353 <p>
5354 Le definizioni per gli estremi di molti dei tipi standard sono:
5355
5356 <tscreen><verb>
5357 G_MINFLOAT
5358 G_MAXFLOAT
5359 G_MINDOUBLE
5360 G_MAXDOUBLE
5361 G_MINSHORT
5362 G_MAXSHORT
5363 G_MININT
5364 G_MAXINT
5365 G_MINLONG
5366 G_MAXLONG
5367 </verb></tscreen>
5368
5369 Ci sono anche le seguenti definizioni di tipo. Quelle rimaste non specificate
5370 sono dipendenti dall'architettura. Si ricordi di evitare di fare affidamento
5371 sulla dimensione di un puntatore se si vuole la portabilit&agrave;! P.e., un puntatore
5372 su un Alpha &egrave; lungo 8 byte, ma 4 su un Intel. 
5373
5374 <tscreen><verb>
5375 char   gchar;
5376 short  gshort;
5377 long   glong;
5378 int    gint;
5379 char   gboolean;
5380
5381 unsigned char   guchar;
5382 unsigned short  gushort;
5383 unsigned long   gulong;
5384 unsigned int    guint;
5385
5386 float   gfloat;
5387 double  gdouble;
5388 long double gldouble;
5389
5390 void* gpointer;
5391
5392 gint8
5393 guint8
5394 gint16
5395 guint16
5396 gint32
5397 guint32
5398 </verb></tscreen>
5399
5400 <sect1>Liste a doppio collegamento
5401 <p>
5402 le seguenti funzioni sono usate per creare, gestire e distruggere liste a
5403 doppio collegamento. Si assume che il lettore sappia gi&agrave; cosa sono le liste
5404 collegate, poich&eacute; descriverle &egrave; fuori dagli scopi di questo documento.
5405 Naturalmente non &egrave; necessario conoscerle per l'uso generale di GTK, per
5406 quanto conoscerle sia comunque interessante.
5407
5408 <tscreen><verb>
5409 GList* g_list_alloc       (void);
5410
5411 void   g_list_free        (GList     *list);
5412
5413 void   g_list_free_1      (GList     *list);
5414
5415 GList* g_list_append      (GList     *list,
5416                            gpointer   data);
5417                            
5418 GList* g_list_prepend     (GList     *list,
5419                            gpointer   data);
5420                         
5421 GList* g_list_insert      (GList     *list,
5422                            gpointer   data,
5423                            gint       position);
5424
5425 GList* g_list_remove      (GList     *list,
5426                            gpointer   data);
5427                            
5428 GList* g_list_remove_link (GList     *list,
5429                            GList     *link);
5430
5431 GList* g_list_reverse     (GList     *list);
5432
5433 GList* g_list_nth         (GList     *list,
5434                            gint       n);
5435                            
5436 GList* g_list_find        (GList     *list,
5437                            gpointer   data);
5438
5439 GList* g_list_last        (GList     *list);
5440
5441 GList* g_list_first       (GList     *list);
5442
5443 gint   g_list_length      (GList     *list);
5444
5445 void   g_list_foreach     (GList     *list,
5446                            GFunc      func,
5447                            gpointer   user_data);
5448 </verb></tscreen>                                             
5449
5450
5451 <sect1>Liste a collegamento singolo
5452 <p>
5453 Molte delle funzioni per le liste a collegamento singolo sono identiche alle
5454 precedenti. Eccone una lista completa:
5455 <tscreen><verb>
5456 GSList* g_slist_alloc       (void);
5457
5458 void    g_slist_free        (GSList   *list);
5459
5460 void    g_slist_free_1      (GSList   *list);
5461
5462 GSList* g_slist_append      (GSList   *list,
5463                              gpointer  data);
5464                 
5465 GSList* g_slist_prepend     (GSList   *list,
5466                              gpointer  data);
5467                              
5468 GSList* g_slist_insert      (GSList   *list,
5469                              gpointer  data,
5470                              gint      position);
5471                              
5472 GSList* g_slist_remove      (GSList   *list,
5473                              gpointer  data);
5474                              
5475 GSList* g_slist_remove_link (GSList   *list,
5476                              GSList   *link);
5477                              
5478 GSList* g_slist_reverse     (GSList   *list);
5479
5480 GSList* g_slist_nth         (GSList   *list,
5481                              gint      n);
5482                              
5483 GSList* g_slist_find        (GSList   *list,
5484                              gpointer  data);
5485                              
5486 GSList* g_slist_last        (GSList   *list);
5487
5488 gint    g_slist_length      (GSList   *list);
5489
5490 void    g_slist_foreach     (GSList   *list,
5491                              GFunc     func,
5492                              gpointer  user_data);
5493         
5494 </verb></tscreen>
5495
5496 <sect1>Gestione della memoria
5497 <p>
5498 <tscreen><verb>
5499 gpointer g_malloc      (gulong    size);
5500 </verb></tscreen>
5501
5502 Questa &egrave; una sostituta di malloc(). Non occorre controllare il valore 
5503 restituito, in quanto lo fa gi&agrave; questa funzione.
5504
5505 <tscreen><verb>
5506 gpointer g_malloc0     (gulong    size);
5507 </verb></tscreen>
5508
5509 Come la precedente, ma la memoria viene azzerata prima di restituire un
5510 puntatore ad essa.
5511
5512 <tscreen><verb>
5513 gpointer g_realloc     (gpointer  mem,
5514                         gulong    size);
5515 </verb></tscreen>
5516
5517 Riloca ``size'' byte di memoria che inizia a ``mem''. Ovviamente, la memoria
5518 dovrebbe essere stata allocata precedentemente.
5519
5520 <tscreen><verb>
5521 void     g_free        (gpointer  mem);
5522 </verb></tscreen>
5523
5524 Libera la memoria. Facile!
5525
5526 <tscreen><verb>
5527 void     g_mem_profile (void);
5528 </verb></tscreen>
5529
5530 Emette un profilo della memoria usata, ma occorre ricompilare e reinstallare
5531 la libreria aggiungendo #define MEM_PROFILE all'inizio del file glib/gmem.c.
5532
5533 <tscreen><verb>
5534 void     g_mem_check   (gpointer  mem);
5535 </verb></tscreen>
5536
5537 Controlla che una locazione di memoria sia valida. Occorre ricompilare e
5538 reinstallare la libreria aggiungendo #define MEM_CHECK all'inizio del file
5539 gmem.c.
5540
5541 <sect1>Timer
5542 <p>
5543 Funzioni legate ai timer...
5544
5545 <tscreen><verb>
5546 GTimer* g_timer_new     (void);
5547
5548 void    g_timer_destroy (GTimer  *timer);
5549
5550 void    g_timer_start   (GTimer  *timer);
5551
5552 void    g_timer_stop    (GTimer  *timer);
5553
5554 void    g_timer_reset   (GTimer  *timer);
5555
5556 gdouble g_timer_elapsed (GTimer  *timer,
5557                          gulong  *microseconds);
5558 </verb></tscreen>                        
5559
5560 <sect1>Gestione delle stringhe
5561 <p>
5562 Un'accozzaglia di funzioni per la gestione delle stringhe. Sembrano tutte molto
5563 interessanti, e probabilmente migliori per molte caratteristiche delle funzioni
5564 standard del C per le stringhe, ma necessitano di documentazione.
5565
5566 <tscreen><verb>
5567 GString* g_string_new       (gchar   *init);
5568 void     g_string_free      (GString *string,
5569                              gint     free_segment);
5570                              
5571 GString* g_string_assign    (GString *lval,
5572                              gchar   *rval);
5573                              
5574 GString* g_string_truncate  (GString *string,
5575                              gint     len);
5576                              
5577 GString* g_string_append    (GString *string,
5578                              gchar   *val);
5579                             
5580 GString* g_string_append_c  (GString *string,
5581                              gchar    c);
5582         
5583 GString* g_string_prepend   (GString *string,
5584                              gchar   *val);
5585                              
5586 GString* g_string_prepend_c (GString *string,
5587                              gchar    c);
5588         
5589 void     g_string_sprintf   (GString *string,
5590                              gchar   *fmt,
5591                              ...);
5592         
5593 void     g_string_sprintfa  (GString *string,
5594                              gchar   *fmt,
5595                              ...);
5596 </verb></tscreen>                                                         
5597
5598 <sect1>Funzioni d'utilit&agrave; e di errore
5599 <p>
5600 <tscreen><verb>
5601 gchar* g_strdup    (const gchar *str);
5602 </verb></tscreen>
5603
5604 Funzione sostitutiva della strdup. Copia i contenuti originari delle stringhe 
5605 in memoria appena allocata, restituendo un puntatore ad essa.
5606
5607 <tscreen><verb>
5608 gchar* g_strerror  (gint errnum);
5609 </verb></tscreen>
5610 Si raccomanda di usare questa gunzione per tutti i messaggi di errore. E' molto
5611 pi&ugrave; graziosa, e pi&ugrave; portabile di perror() o di altre. L'output di solito ha la
5612 forma:
5613
5614 <tscreen><verb>
5615 nome programma:funzione fallita:file o altre descrizioni:strerror
5616 </verb></tscreen>
5617
5618 Di seguito un esempio di una chiamata di questo tipo usata nel nostro
5619 programma Hello World:
5620
5621 <tscreen><verb>
5622 g_print("hello_world:open:%s:%s\n", filename, g_strerror(errno));
5623 </verb></tscreen>
5624
5625 <tscreen><verb>
5626 void g_error   (gchar *format, ...);
5627 </verb></tscreen>
5628
5629 Visualizza un messaggio di errore. Il formato &egrave; come quello di printf,
5630 ma prepone ``** ERROR **: '' al messaggio e termina il programma. Da usare solo
5631 per errori gravi.
5632
5633 <tscreen><verb>
5634 void g_warning (gchar *format, ...);
5635 </verb></tscreen>
5636
5637 Come la precedente, ma prepone ``** WARNING **: '' e non termina il programma.
5638
5639 <tscreen><verb>
5640 void g_message (gchar *format, ...);
5641 </verb></tscreen>
5642
5643 Visualizza ``message: '' e poi il messaggio.
5644
5645 <tscreen><verb>
5646 void g_print   (gchar *format, ...);
5647 </verb></tscreen>
5648
5649 Sostituta di printf().
5650
5651 L'ultima funzione:
5652
5653 <tscreen><verb>
5654 gchar* g_strsignal (gint signum);
5655 </verb></tscreen>
5656
5657 Visualizza il nome del messaggio del sistema Unix associato al numero di
5658 segnale. Utile nelle funzioni generiche di gestione dei segnali.
5659
5660 Tutte le funzioni elencate sono pi&ugrave; o meno prese da glib.h. Se qualcuno volesse
5661 documentare qualche funzione, mandi una email all'autore!
5662
5663 <sect>I file rc di GTK
5664 <p>
5665 GTK ha un suo modo di trattare le preferenze delle applicazioni, usando
5666 i file rc. Questi possono essere usati per scegliere i colori di quasi tutti
5667 i widget, e possono anche essere usati per inserire delle pixmap nello sfondo
5668 di alcuni widget.
5669
5670 <sect1>Funzioni per i file rc
5671 <p>
5672 All'inizio della vostra applicazione dovrebbe esserci una chiamata a
5673 <tscreen><verb>
5674 void gtk_rc_parse (char *filename);
5675 </verb></tscreen>
5676 <p>
5677 passando come parametro il nome del vostro file rc. Questo far&agrave; si che GTK
5678 analizzi tale file e usi le impostazioni di stile per i tipi di widget ivi
5679 definite.
5680 <p>
5681 Se si desidera avere un insieme speciale di widget che abbia uno stile diverso
5682 dagli altri, o qualsiasi altra divisione logica dei widget, si chiami
5683 <tscreen><verb>
5684 void gtk_widget_set_name (GtkWidget *widget,
5685                           gchar *name);
5686 </verb></tscreen>
5687 <p>
5688 passando un widget appena creato come primo argomento, e il nome che gli si
5689 vuole dare come secondo. Questo consentir&agrave; di cambiare gli attributi di
5690 questo widget per nome tramite il file rc.
5691 <p>
5692 Effettuando una chiamata come questa:
5693
5694 <tscreen><verb>
5695 button = gtk_button_new_with_label ("Special Button");
5696 gtk_widget_set_name (button, "special button");
5697 </verb></tscreen>
5698 <p>
5699 allora a questo bottone viene dato il nome ``special button'' ed esso pu&ograve; essere
5700 riferito per nome nel file rc come ``special button.GtkButton''. [<--- Verificatemi!]
5701 <p>
5702 Il seguente esempio di file rc imposta le propriet&agrave; della finestra principale,
5703 e fa si che tutti i figli di questa finestra ereditino lo stile descritto
5704 dallo stile ``main button''. Il codice usato nell'applicazione &egrave;:
5705
5706 <tscreen><verb>
5707 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
5708 gtk_widget_set_name (window, "main window");
5709 </verb></tscreen>
5710 <p>
5711 Lo stile viene definito nel file rc usando:
5712
5713 <tscreen><verb>
5714 widget "main window.*GtkButton*" style "main_button"
5715 </verb></tscreen>
5716 <p>
5717 che assegna a tutti i widget GtkButton nella finestra principale lo stile
5718 ``main_buttons'' secondo la definizione data nel file rc.
5719 <p>
5720 Come si pu&ograve; vedere, questo sistema &egrave; molto potente e flessibile. Usate la
5721 vostra immaginazione per trarre il massimo vantaggio da esso.
5722
5723 <sect1>Il formato dei file rc di GTK
5724 <p>
5725 Nell'esempio che segue viene illustrato il formato del file GTK. Si tratta
5726 del file testgkrc dalla distribuzione del GTK, a cui sono stati aggiunti
5727 vari commenti e varie cose. Potete includere questa spiegazione nella
5728 vostra applicazione per consentire all'utente di personalizzarla finemente.
5729 <p>
5730 There are several directives to change the attributes of a widget.
5731 Ci sono diverse direttive per cambiare gli attributi di un widget.
5732 <itemize>
5733 <item>fg - Assegna il colore di primo piano di un widget.
5734 <item>bg - Assegna il colore di sfondo di un widget.
5735 <item>bg_pixmap - Inserisce nello sfondo di un widget una pixmap.
5736 <item>font - Sceglie il font da usarsi con il dato widget.
5737 </itemize>
5738 <p>
5739 Inoltre ci sono diversi stati in cui pu&ograve; trovarsi un widget, e si possono
5740 assegnare diversi colori, pixmap e font per ogni stato. Essi sono:
5741 <itemize>
5742 <item>NORMAL - Lo stato normale di un widget, quando il mouse non si trova su
5743 di esso, quando non &egrave; premuto, ecc.
5744 <item>PRELIGHT (evidenziato)- Quando il mouse si trova sopra al widget
5745 verranno usati i colori assegnati per questo stato.
5746 <item>ACTIVE (attivo) - Quando il widget &egrave; premuto o cliccato esso sar&agrave; attivo,
5747 e verranno usati gli attributi assegnati da questa etichetta.
5748 <item>INSENSITIVE (insensibile)- Quando un widget viene reso insensibile,
5749 e non pu&ograve; essere attivato, prender&agrave; questi attributi.
5750 <item>SELECTED (selezionato) - Quando un oggetto viene selezionato, prende
5751 questi attributi.
5752 </itemize>
5753 <p>
5754 Quando si usano le parole chiave ``fg'' e ``bg'' per assegnare i colori dei 
5755 widget il formato &egrave;:
5756 <tscreen><verb>
5757 fg[<STATE>] = { Rosso, Verde, Blu }
5758 </verb></tscreen>
5759 <p>
5760 Dove STATE &egrave; uno degli stati visti prima (PRELIGHT, ACTIVE ecc.), e Rosso,
5761 Verde e Blu sono valori nell'intervallo 0 - 1.0;  { 1.0, 1.0, 1.0 } rappresenta
5762 il bianco.
5763 Devono essere in formato float, o verranno visti come 0, sicch&eacute; un ``1'' diretto
5764 non funziona, deve essere ``1.0''. Uno ``0'' diretto va invece bene, poich&eacute; poco
5765 importa se non viene riconosciuto: valori non riconosciuti vengono considerati
5766 0.
5767 <p>
5768 bg_pixmap &egrave; molto simile al precedente, tranne per i colori che vengono
5769 sostituiti dal nome di un file.
5770
5771 pixmap_path &egrave; una lista di percorsi separati da ``:''. In questi percorsi vengono
5772 cercate le pixmap specificate.
5773 <p>
5774 La direttiva font &egrave; semplicemente:
5775 <tscreen><verb>
5776 font = "<font name>"
5777 </verb></tscreen>
5778 <p>
5779 dove l'unica parte complicata &egrave; immaginare la stringa del font. Allo scopo
5780 pu&ograve; servire usare xfontsel o una utilit&agrave; analoga.
5781 <p>
5782 ``widget_class'' assegna lo stile di una classe di widget. Queste classi sono
5783 elencate nell'introduzione ai widget sulla gerarchia delle classi.
5784 <p>
5785 La direttiva ``widget'' assegna un insieme di widget dal nome specificato ad
5786 un dato stile, annullando qualsiasi stile assegnato per la data classe di widget.
5787 Questi widget vengono registrati nell'applicazione usando la chiamata
5788 gtk_widget_set_name(). Questo consente di specificare gli attributi di un
5789 widget singlarmente, piuttosto che assegnando gli attributi di un'intera classe
5790 di widget. E' opportuno documentare tutti questi widget speciali in modo che
5791 gli utenti possano personalizzarli.
5792 <p>
5793 Quando la parola chiave ``<tt>parent</>'' viene usata come un attributo, il
5794 widget erediter&agrave; gli attributi del suo genitore nell'applicazione.
5795 <p>
5796 Quando si definisce uno stile si possono assegnare gli attributi di uno
5797 stile definito precedentemente a quello nuovo.
5798 <tscreen><verb>
5799 style "main_button" = "button"
5800 {
5801   font = "-adobe-helvetica-medium-r-normal--*-100-*-*-*-*-*-*"
5802   bg[PRELIGHT] = { 0.75, 0, 0 }
5803 }
5804 </verb></tscreen>
5805 <p>
5806 Questo esempio prende lo stile ``button'' e crea un nuovo stile 
5807 semplicemente cambiando il font e il colore di sfondo dello stato ``prelight''
5808 nello stile ``button''.
5809 <p>
5810 Naturalmente, molti di questi attributi non sono applicabili a tutti i widget.
5811 E' veramente un semplice problema di buon senso. Tutto quello che potrebbe
5812 applicarsi, dovrebbe.
5813
5814 <sect1>Esempio di file rc 
5815 <p>
5816
5817 <tscreen><verb>
5818 # pixmap_path "<dir 1>:<dir 2>:<dir 3>:..."
5819 #
5820 pixmap_path "/usr/include/X11R6/pixmaps:/home/imain/pixmaps"
5821 #
5822 # style <name> [= <name>]
5823 # {
5824 #   <option>
5825 # }
5826 #
5827 # widget <widget_set> style <style_name>
5828 # widget_class <widget_class_set> style <style_name>
5829
5830
5831 # Ecco una lista di tutti gli stati possibili. Si noti che alcuni non sono
5832 # applicabili a certi widget.
5833 #
5834 # NORMAL - Lo stato normale di un widget, quando il mouse non si trova su
5835 # di esso, quando non &egrave; premuto, ecc.
5836 #
5837 # PRELIGHT (evidenziato)- Quando il mouse si trova sopra al widget
5838 # verranno usati i colori assegnati per questo stato.
5839 #
5840 # ACTIVE (attivo) - Quando il widget &egrave; premuto o cliccato esso sar&agrave; attivo,
5841 # e verranno usati gli attributi assegnati da questa etichetta.
5842 #
5843 # INSENSITIVE (insensibile)- Quando un widget viene reso insensibile,
5844 # e non pu&ograve; essere attivato, prender&agrave; questi attributi.
5845 #
5846 # SELECTED (selezionato) - Quando un oggetto viene selezionato, prende
5847 # questi attributi.
5848 #
5849 # Dati questi stati, &egrave; possibile assegnare gli attributi dei widget in
5850 # ognuno di questi stati usando le seguenti direttive.
5851 #
5852 # fg - Assegna il colore di primo piano di un widget.
5853 # bg - Assegna il colore di sfondo di un widget.
5854 # bg_pixmap - Inserisce nello sfondo di un widget una pixmap.
5855 # font - Sceglie il font da usarsi con il dato widget.
5856 #
5857
5858 # Questo &egrave; uno stile chiamato "button". Il nome non &egrave; veramente importante,
5859 # in quanto viene assegnato ai veri widget alla fine del file. 
5860
5861 style "window"
5862 {
5863   # Questo inserisce nella spaziatura attorno alla finestra la pixmap
5864   # specificata.
5865   #bg_pixmap[<STATE>] = "<pixmap filename>"
5866   bg_pixmap[NORMAL] = "warning.xpm"
5867 }
5868
5869 style "scale"
5870 {
5871   # Mette il colore di primo piano (il colore del font) a rosso nello
5872   # stato "NORMAL".
5873   
5874   fg[NORMAL] = { 1.0, 0, 0 }
5875   
5876   # Inserisce nello sfondo del gadget la stessa pixmap usata dal suo genitore.
5877   bg_pixmap[NORMAL] = "<parent>"
5878 }
5879
5880 style "button"
5881 {
5882   # Questo mostra tutti i possibili stati per un bottone. L'unico che
5883   # non &egrave; applicabile &egrave; lo stato "SELECTED".
5884   
5885   fg[PRELIGHT] = { 0, 1.0, 1.0 }
5886   bg[PRELIGHT] = { 0, 0, 1.0 }
5887   bg[ACTIVE] = { 1.0, 0, 0 }
5888   fg[ACTIVE] = { 0, 1.0, 0 }
5889   bg[NORMAL] = { 1.0, 1.0, 0 }
5890   fg[NORMAL] = { .99, 0, .99 }
5891   bg[INSENSITIVE] = { 1.0, 1.0, 1.0 }
5892   fg[INSENSITIVE] = { 1.0, 0, 1.0 }
5893 }
5894
5895 # In questi esempio ereditiamo gli attributi dello stile "button" e poi
5896 # alteriamo il font e il colore di sfondo quando evidenziato per creare
5897 # un nuovo stile "main_button".
5898
5899 style "main_button" = "button"
5900 {
5901   font = "-adobe-helvetica-medium-r-normal--*-100-*-*-*-*-*-*"
5902   bg[PRELIGHT] = { 0.75, 0, 0 }
5903 }
5904
5905 style "toggle_button" = "button"
5906 {
5907   fg[NORMAL] = { 1.0, 0, 0 }
5908   fg[ACTIVE] = { 1.0, 0, 0 }
5909   
5910   # Questo seleziona come pixmap di sfondo per il toggle_button quella del
5911   # suo widget genitore (definita nell'applicazione).
5912   bg_pixmap[NORMAL] = "<parent>"
5913 }
5914
5915 style "text"
5916 {
5917   bg_pixmap[NORMAL] = "marble.xpm"
5918   fg[NORMAL] = { 1.0, 1.0, 1.0 }
5919 }
5920
5921 style "ruler"
5922 {
5923   font = "-adobe-helvetica-medium-r-normal--*-80-*-*-*-*-*-*"
5924 }
5925
5926 # pixmap_path "~/.pixmaps"
5927
5928 # Queste assegnano ai tipi di widget gli stili definiti prima.
5929 # I tipi di widget sono elencati nella gerarchia delle classi, ma probabilmente
5930 # dovrebbero essere elencati in questo documento come riferimento per l'utente.
5931
5932 widget_class "GtkWindow" style "window"
5933 widget_class "GtkDialog" style "window"
5934 widget_class "GtkFileSelection" style "window"
5935 widget_class "*Gtk*Scale" style "scale"
5936 widget_class "*GtkCheckButton*" style "toggle_button"
5937 widget_class "*GtkRadioButton*" style "toggle_button"
5938 widget_class "*GtkButton*" style "button"
5939 widget_class "*Ruler" style "ruler"
5940 widget_class "*GtkText" style "text"
5941
5942 # Questo assegna lo stile main_button a tutti i bottoni che sono figli della
5943 # "main window" (finestra principale). Questi devono essere documenati per
5944 # potersene avvantaggiare.
5945 widget "main window.*GtkButton*" style "main_button"
5946 </verb></tscreen>
5947
5948
5949
5950 <sect>Scrivere un proprio Widget
5951
5952 <p>
5953 <sect1> Panoramica
5954 <p>
5955 Anche se la distribuzione GTK contiene molto tipi di widget che possono
5956 coprire molte necessit&agrave; basilari, pu&ograve; essere necessario costruirsi
5957 un proprio widget. GTK usa molto l'ereditariet&agrave; tra i vari
5958 widget e, di solito, vi &egrave; un widget che si avvicina a quello che ti
5959 servirebbe, ed &egrave; spesso possibile creare un nuovo widget con poche linee
5960 di codice. Ma prima di iniziare il lavoro su un nuovo widget, vediamo 
5961 se qualcuno non lo ha gi&agrave; creato. Questo eviter&agrave; un duplicazione
5962 di lavoro e far&agrave; s&igrave; che i widget non-GTK puri siano minimi, cos&igrave; da
5963 aiutare sia chi crea il codice che chi l'interfaccia per applicazioni GTK 
5964 molto grosse. D'altra parte, quando hai finito di scrivere un widget, 
5965 annuncialo a tutto il mondo cos&igrave; che le altre persone ne possano
5966 beneficiare. Il miglioro modo dove farlo &egrave; la  <tt>gtk-list</tt>.
5967
5968 <sect1> L'anatomia di un widget
5969
5970 <p>
5971 Per creare un nuovo widget &egrave; importante aver capito come gli ogetti 
5972 di GTK lavorano. Questa sezione &egrave; solo una breve spiegazione. Guarda la
5973 documentazione di riferimento per maggiori dettagli.
5974
5975 <p>
5976 I widget GTK sono implementati in un modo orientato agli oggetti,
5977 anche se usando il C standard. Questo aumenta notevolmente la portabilit&agrave;
5978 e la stabilit&agrave;, specialmente per le correnti generazioni di compilatori C++;
5979 comunque questo significa che chi scrive un widget deve fare attenzione
5980 ad alcuni dettagli di implementazione. L'informazione comune a tutte le
5981 istanze di una classe di widget (ad esempio: a tutti i bottoni) &egrave; memorizzata 
5982 <em>class structure</em>. C'e' solamente una copia di questo in cui 
5983 sono memorizzate le informazioni riguardanti i segnali della classe 
5984 (assomiglia ad una funzione virtuale in C). Per supportare l'ereditariet&agrave;
5985 il primo campo della struttura di una classe deve essere una copia della
5986 struttura della classe genitore. La dichiarazione della struttura della 
5987 classe GtkButton &egrave;:
5988
5989 <tscreen><verb>
5990 struct _GtkButtonClass
5991 {
5992   GtkContainerClass parent_class;
5993
5994   void (* pressed)  (GtkButton *button);
5995   void (* released) (GtkButton *button);
5996   void (* clicked)  (GtkButton *button);
5997   void (* enter)    (GtkButton *button);
5998   void (* leave)    (GtkButton *button);
5999 };
6000 </verb></tscreen>
6001
6002 <p>
6003 Quando un bottone viene trattato come un contenitore (ad esempio quando viene 
6004 ridimensionato) si pu&ograve; fare il cast della struttura della sua classe con la 
6005 GtkContainerClass, e usare i campi rilevanti per gestire i segnali.
6006
6007 <p>
6008 C'&egrave; anche una struttura per ogni widget che viene creata 
6009 ad ogni istanza. Questa struttura ha campi per 
6010 memorizzare le informazioni che sono differenti per ogni volta che il widget
6011 viene istanziato. Chiameremo questa struttura la <em> struttura
6012 oggetto</em>. Per la classe Bottone, questa ha l'aspetto:
6013
6014 <tscreen><verb>
6015 struct _GtkButton
6016 {
6017   GtkContainer container;
6018
6019   GtkWidget *child;
6020
6021   guint in_button : 1;
6022   guint button_down : 1;
6023 };
6024 </verb></tscreen>
6025
6026 <p>
6027 Si noti che, similmente alla struttura della classe, il primo campo
6028 &egrave; la struttura dell'oggetto della classe madre, cos&igrave; che, se necessario, si pu&ograve; fare il
6029 cast di questa struttura con quella dell'oggetto della classe madre.
6030
6031 <sect1> Creare un Widget composto
6032
6033 <sect2> Introduzione
6034
6035 <p>
6036 Un tipo di widget a cui potreste essere interessati &egrave; un widget che
6037 &egrave; semplicemnte un aggregato di altri widget GTK. Questo tipo di 
6038 widget non fa nulla che non possa essere fatto creando un nuovo
6039 widget, ma fornisce un modo conveniente per inscatolare elementi 
6040 dell'interfaccia utente per poi riutilizzarli. 
6041 I widget FileSelection e ColorSelection della ditribuzione standard
6042 sono esempi di questo tipo di widget.
6043
6044 <p>
6045 Il widget di esempio che creeremo in questo capitolo &egrave; il 
6046 Tictactoe, un vettore 3x3 di bottoni a commutazione il quale emette
6047 un segnale quando tutti e 3 i bottoni di una riga, colonna o di una
6048 diagonale sono premuti.
6049
6050 <sect2> Scegliere la classe madre
6051
6052 <p>
6053 La classe madre per un widget composto e' tipicamente la classe 
6054 contenitrice che racchiude tutti gli elementi del widget composto.
6055 Per esempio, la classe madre del widget FileSelection &egrave; la classe
6056 Dialog. Visto che i nostri bottoni sono inseriti in una tabella, &egrave; 
6057 naturale pensare che la nostra classe madre possa essere la GtkTable.
6058 Sfortunatamente, cos&igrave; non &egrave;. La creazione di un widget &egrave; diviso
6059 tra 2 funzioni : la funzione <tt/WIDGETNAME_new()/ che viene invocata
6060 dall'utente, e la funzione  <tt/WIDGETNAME_init()/ che ha il compito
6061 principale di inizializzare il widget che &egrave; indipendente dai valori
6062 passati alla funzione <tt/_new()/. Widget figli o discendenti  possono 
6063 chiamare, solamente, la funzione del loro widget genitore. 
6064 Ma questa divisione del lavoro non funziona bene per la tabella, la
6065 quale, quando creata, necessita di conoscere il numero di righe e
6066 colonne che la comporr&agrave;. A meno che non vogliamo duplicare molte delle 
6067 fuinzionalit&agrave; della <tt/gtk_table_new()/ nel nostro widget
6068 Tictactoe, faremmo meglio a evitare di derivarlo dalla GtkTable. Per questa
6069 ragione lo deriviamo invece da GtkVBox, e uniamo la nostra tabella
6070 dentro il VBox.
6071
6072 <sect2> Il File Header
6073
6074 <p>
6075 Ogni classe di widget ha un file header il quale dichiara l'oggetto e la
6076 struttura della classe del widget, comprese le funzioni pubbliche.
6077 Per prevenire duplicati di definizioni, noi includiamo l'intero file header fra:
6078
6079 <tscreen><verb>
6080 #ifndef __TICTACTOE_H__
6081 #define __TICTACTOE_H__
6082 .
6083 .
6084 .
6085 #endif /* __TICTACTOE_H__ */
6086 </verb></tscreen>
6087
6088 E per far felici i programmi in C++ che includono il nostro file header, in:
6089
6090 <tscreen><verb>
6091 #ifdef __cplusplus
6092 extern "C" {
6093 #endif /* __cplusplus */
6094 .
6095 .
6096 .
6097 #ifdef __cplusplus
6098 }
6099 #endif /* __cplusplus */
6100 </verb></tscreen>
6101
6102 Insieme alle funzioni e alle strutture, dichiariamo tre macro 
6103 standard nel nostro file header, <tt/TICTACTOE(obj)/,
6104 <tt/TICTACTOE_CLASS(klass)/, e <tt/IS_TICTACTOE(obj)/, i quali rispettivamente 
6105 fanno il cast di un puntatore ad un puntatore ad un ogetto od ad una struttura
6106 di classe, e guarda se un oggetto &egrave; un widget Tictactoe.
6107
6108
6109 Qui vi &egrave; il file header completo:
6110
6111 <tscreen><verb>
6112
6113 #ifndef __TICTACTOE_H__
6114 #define __TICTACTOE_H__
6115
6116 #include <gdk/gdk.h>
6117 #include <gtk/gtkvbox.h>
6118
6119 #ifdef __cplusplus
6120 extern "C" {
6121 #endif /* __cplusplus */
6122
6123 #define TICTACTOE(obj)          GTK_CHECK_CAST (obj, tictactoe_get_type (), Tictactoe)
6124 #define TICTACTOE_CLASS(klass)  GTK_CHECK_CLASS_CAST (klass, tictactoe_get_type (), TictactoeClass)
6125 #define IS_TICTACTOE(obj)       GTK_CHECK_TYPE (obj, tictactoe_get_type ())
6126
6127
6128 typedef struct _Tictactoe       Tictactoe;
6129 typedef struct _TictactoeClass  TictactoeClass;
6130
6131 struct _Tictactoe
6132 {
6133   GtkVBox vbox;
6134   
6135   GtkWidget *buttons[3][3];
6136 };
6137
6138 struct _TictactoeClass
6139 {
6140   GtkVBoxClass parent_class;
6141
6142   void (* tictactoe) (Tictactoe *ttt);
6143 };
6144
6145 guint          tictactoe_get_type        (void);
6146 GtkWidget*     tictactoe_new             (void);
6147 void           tictactoe_clear           (Tictactoe *ttt);
6148
6149 #ifdef __cplusplus
6150 }
6151 #endif /* __cplusplus */
6152
6153 #endif /* __TICTACTOE_H__ */
6154
6155 </verb></tscreen>
6156
6157 <sect2> La funzione <tt/_get_type()/
6158
6159 <p>
6160 Continuiamo ora con l'implementazione del nostro widget. Una funzione
6161 basilare di ogni widget &egrave; la funzione <tt/WIDGETNAME_get_type()/.
6162 Questa funzione, quando chiamata la prima volta, comunica a GTK la classe 
6163 del widget, e ottiene un identificativo univoco per la classe del
6164 widget. Chiamate successive restituiscono semplicemente l'identificativo.
6165
6166 <tscreen><verb>
6167 guint
6168 tictactoe_get_type ()
6169 {
6170   static guint ttt_type = 0;
6171
6172   if (!ttt_type)
6173     {
6174       GtkTypeInfo ttt_info =
6175       {
6176         "Tictactoe",
6177         sizeof (Tictactoe),
6178         sizeof (TictactoeClass),
6179         (GtkClassInitFunc) tictactoe_class_init,
6180         (GtkObjectInitFunc) tictactoe_init,
6181         (GtkArgFunc) NULL,
6182       };
6183
6184       ttt_type = gtk_type_unique (gtk_vbox_get_type (), &amp;ttt_info);
6185     }
6186
6187   return ttt_type;
6188 }
6189 </verb></tscreen>
6190
6191 <p>
6192 La struttura GtkTypeInfo ha la seguente definizione:
6193
6194 <tscreen><verb>
6195 struct _GtkTypeInfo
6196 {
6197   gchar *type_name;
6198   guint object_size;
6199   guint class_size;
6200   GtkClassInitFunc class_init_func;
6201   GtkObjectInitFunc object_init_func;
6202   GtkArgFunc arg_func;
6203 };
6204 </verb></tscreen>
6205
6206 <p>
6207 I campi di questa struttura sono abbastanza auto-esplicativi.
6208 Ignoreremo, per ora, il campo <tt/arg_func/: ha un ruolo importante, ma
6209 non ancora largamente implementato, nel permettere ai linguaggi interpretati
6210 di settare convenientemente le opzioni del widget.
6211 Una volta che il GTK ha completato correttamente una copia di questa
6212 struttura, sa come creare un oggetto di un particolare widget.
6213
6214 <sect2> La funzione <tt/_class_init()/ 
6215 <p>
6216 La funzione <tt/WIDGETNAME_class_init()/ inizialiazza i campi della
6217 struttura della classe del widget, e setta ogni segnale della classe.
6218 Per il nostro widget Tictactoe ha il seguente aspetto:
6219
6220 <tscreen><verb>
6221
6222 enum {
6223   TICTACTOE_SIGNAL,
6224   LAST_SIGNAL
6225 };
6226
6227 static gint tictactoe_signals[LAST_SIGNAL] = { 0 };
6228
6229 static void
6230 tictactoe_class_init (TictactoeClass *class)
6231 {
6232   GtkObjectClass *object_class;
6233
6234   object_class = (GtkObjectClass*) class;
6235   
6236   tictactoe_signals[TICTACTOE_SIGNAL] = gtk_signal_new ("tictactoe",
6237                                          GTK_RUN_FIRST,
6238                                          object_class->type,
6239                                          GTK_SIGNAL_OFFSET (TictactoeClass, tictactoe),
6240                                          gtk_signal_default_marshaller, GTK_ARG_NONE, 0);
6241
6242
6243   gtk_object_class_add_signals (object_class, tictactoe_signals, LAST_SIGNAL);
6244
6245   class->tictactoe = NULL;
6246 }
6247 </verb></tscreen>
6248
6249 <p>
6250 Il nostro  widget ha semplicemente il segnale ``tictactoe'' che &egrave;
6251 invocato quando una riga, colonna o diagonale &egrave; completamente premuta.
6252 Non tutti i widget composti necessitano di segnali, quindi se stai
6253 leggendo questo per la prima volta, puoi anche saltare alla prossima sezione,
6254 dal momento che a questo punto le cose diventano un po' complicate.
6255
6256 La funzione:
6257 <tscreen><verb>
6258 gint   gtk_signal_new                     (gchar               *name,
6259                                            GtkSignalRunType     run_type,
6260                                            gint                 object_type,
6261                                            gint                 function_offset,
6262                                            GtkSignalMarshaller  marshaller,
6263                                            GtkArgType           return_val,
6264                                            gint                 nparams,
6265                                            ...);
6266 </verb></tscreen>
6267
6268 crea un nuovo segnale. I parametri sono:
6269
6270 <itemize>
6271 <item> <tt/name/: Il nome del segnale.
6272 <item> <tt/run_type/: Se il segstore predefinito viene eseguito prima o dopo
6273 di quello dell'utente. Di norma questo sar&agrave; <tt/GTK_RUN_FIRST/, o <tt/GTK_RUN_LAST/,
6274 anche se ci sono altre possibilit&agrave;.
6275 <item> <tt/object_type/: l'identificativo dell'oggetto a cui questo segnale si 
6276 riferisce. Esso sar&agrave; anche applicato agli oggetti discendenti.
6277 <item> <tt/function_offset/: L'offset nella struttura della classe di un
6278 puntatore al gestore predefinito.
6279 <item> <tt/marshaller/: una funzione che &egrave; usata per invocare il gestore
6280 del segnale. Per gestori di segnali che non hanno argomenti oltre 
6281 all'oggetto che emette il segnale e i dati dell'utente, possiamo usare
6282 la funzione predefinita <tt/gtk_signal_default_marshaller/
6283 <item> <tt/return_val/: Il tipo del valore di ritorno.
6284 <item> <tt/nparams/: Il numero di parametri del gestore di segnali (oltre
6285 ai due predefiniti menzionati sopra)
6286 <item> <tt/.../: i tipi dei parametri
6287 </itemize>
6288
6289 Quando si specificano i tipi, si usa l'enumerazione <tt/GtkArgType/:
6290
6291 <tscreen><verb>
6292 typedef enum
6293 {
6294   GTK_ARG_INVALID,
6295   GTK_ARG_NONE,
6296   GTK_ARG_CHAR,
6297   GTK_ARG_SHORT,
6298   GTK_ARG_INT,
6299   GTK_ARG_LONG,
6300   GTK_ARG_POINTER,
6301   GTK_ARG_OBJECT,
6302   GTK_ARG_FUNCTION,
6303   GTK_ARG_SIGNAL
6304 } GtkArgType;
6305 </verb></tscreen>
6306
6307 <p>
6308 <tt/gtk_signal_new()/ restituisce un identificatore unico intero per il segnale, 
6309 che memorizziamo nel vettore  <tt/tictactoe_signals/, che
6310 indicizzeremo usando una enumerazione. (Convenzionalmente, gli elementi dell'enumerazione
6311 sono i nomi dei segnali, in maiuscolo, 
6312 ma qui ci potrebbe essere un conflitto con la macro <tt/TICTACTOE()/, 
6313 quindi l'abbiamo chiamato  <tt/TICTACTOE_SIGNAL/
6314
6315 Dopo aver creato un nostro segnale, abbiamo bisogno di dire a GTK
6316 di associare il nostro segnale alla classe Tictactoe. Lo facciamo
6317 invocando <tt/gtk_object_class_add_signals()/. Settiamo quindi a NULL
6318 il puntatore che punta al gestore predefinito per il segnale 
6319 ``tictactoe'' a NULL, indicando che non ci sono azioni predefinite.
6320
6321 <sect2> La funzione <tt/_init()/
6322
6323 <p>
6324
6325 Ogni classe di Widget necessita anche di una funzione per inizializzare 
6326 la struttura dell'oggetto. Usualmente questa funzione ha il ruolo abbastanza
6327 limitato di assegnare ai campi della struttura i valori predefiniti.
6328 Per widget composti, comunque, questa funzione crea, anche,
6329 i widget componenti del widget composto.
6330
6331 <tscreen><verb>
6332
6333 static void
6334 tictactoe_init (Tictactoe *ttt)
6335 {
6336   GtkWidget *table;
6337   gint i,j;
6338   
6339   table = gtk_table_new (3, 3, TRUE);
6340   gtk_container_add (GTK_CONTAINER(ttt), table);
6341   gtk_widget_show (table);
6342
6343   for (i=0;i<3; i++)
6344     for (j=0;j<3; j++)
6345       {
6346         ttt->buttons[i][j] = gtk_toggle_button_new ();
6347         gtk_table_attach_defaults (GTK_TABLE(table), ttt->buttons[i][j], 
6348                                    i, i+1, j, j+1);
6349         gtk_signal_connect (GTK_OBJECT (ttt->buttons[i][j]), "toggled",
6350                             GTK_SIGNAL_FUNC (tictactoe_toggle), ttt);
6351         gtk_widget_set_usize (ttt->buttons[i][j], 20, 20);
6352         gtk_widget_show (ttt->buttons[i][j]);
6353       }
6354 }
6355 </verb></tscreen>
6356
6357 <sect2> E il resto...
6358
6359 <p>
6360
6361 C'&egrave; un'altra funzione che ogni widget (eccetto i Widget di base come 
6362 GtkBin che non possono essere instanziati) deve avere : la funzione
6363 che l'utente invoca per creare un oggetto di quel tipo. Questa &egrave; 
6364 convenzionalmente chiamata <tt/WIDGETNAME_new()/. In alcuni widget,
6365 non nel caso del nostro Tictactoe, questa funzione richiede degli 
6366 argomenti, e fa alcune operazioni basandosi su di essi. Le altre
6367 due funzioni sono specifiche del widget Tictactoe.
6368
6369 <p>
6370 <tt/tictactoe_clear()/ &egrave; una funzione pubblica che resetta tutti i 
6371 bottoni, nel widget, allo stato iniziale (non premuto). Notate l'uso 
6372 di <tt/gtk_signal_handler_block_by_data()/ per impedire che il nostro
6373 gestore dei segnali venga attivato quando non ce n'&egrave; bisogno.
6374
6375 <p>
6376 <tt/tictactoe_toggle()/ &egrave; il gestore del segnale che viene invocato 
6377 quando l'utente preme il bottone. Esso guarda se vi &egrave;
6378 qualche combinazione vincente che coinvolge i bottoni premuti, e nel
6379 caso ci fosse, emette il segnale ``tictactoe''.
6380
6381 <tscreen><verb>  
6382 GtkWidget*
6383 tictactoe_new ()
6384 {
6385   return GTK_WIDGET ( gtk_type_new (tictactoe_get_type ()));
6386 }
6387
6388 void           
6389 tictactoe_clear (Tictactoe *ttt)
6390 {
6391   int i,j;
6392
6393   for (i=0;i<3;i++)
6394     for (j=0;j<3;j++)
6395       {
6396         gtk_signal_handler_block_by_data (GTK_OBJECT(ttt->buttons[i][j]), ttt);
6397         gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (ttt->buttons[i][j]),
6398                                      FALSE);
6399         gtk_signal_handler_unblock_by_data (GTK_OBJECT(ttt->buttons[i][j]), ttt);
6400       }
6401 }
6402
6403 static void
6404 tictactoe_toggle (GtkWidget *widget, Tictactoe *ttt)
6405 {
6406   int i,k;
6407
6408   static int rwins[8][3] = { { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 },
6409                              { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 },
6410                              { 0, 1, 2 }, { 0, 1, 2 } };
6411   static int cwins[8][3] = { { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 },
6412                              { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 },
6413                              { 0, 1, 2 }, { 2, 1, 0 } };
6414
6415   int success, found;
6416
6417   for (k=0; k<8; k++)
6418     {
6419       success = TRUE;
6420       found = FALSE;
6421
6422       for (i=0;i<3;i++)
6423         {
6424           success = success &amp;&amp; 
6425             GTK_TOGGLE_BUTTON(ttt->buttons[rwins[k][i]][cwins[k][i]])->active;
6426           found = found ||
6427             ttt->buttons[rwins[k][i]][cwins[k][i]] == widget;
6428         }
6429       
6430       if (success &amp;&amp; found)
6431         {
6432           gtk_signal_emit (GTK_OBJECT (ttt), 
6433                            tictactoe_signals[TICTACTOE_SIGNAL]);
6434           break;
6435         }
6436     }
6437 }
6438 </verb></tscreen>
6439
6440 <p>
6441
6442 E finalmente un programma di esempio che usa il nostro widget
6443 Tictactoe:
6444
6445 <tscreen><verb>
6446 #include <gtk/gtk.h>
6447 #include "tictactoe.h"
6448
6449 /* Invocato quando una riga, colonna o diagonale e' completata. */
6450 void
6451 win (GtkWidget *widget, gpointer data)
6452 {
6453   g_print ("Yay!\n");
6454   tictactoe_clear (TICTACTOE (widget));
6455 }
6456
6457 int 
6458 main (int argc, char *argv[])
6459 {
6460   GtkWidget *window;
6461   GtkWidget *ttt;
6462   
6463   gtk_init (&amp;argc, &amp;argv);
6464
6465   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
6466   
6467   gtk_window_set_title (GTK_WINDOW (window), "Aspect Frame");
6468   
6469   gtk_signal_connect (GTK_OBJECT (window), "destroy",
6470                       GTK_SIGNAL_FUNC (gtk_exit), NULL);
6471   
6472   gtk_container_border_width (GTK_CONTAINER (window), 10);
6473
6474   /* Crea un nuovo widget Tictactoe. */
6475   ttt = tictactoe_new ();
6476   gtk_container_add (GTK_CONTAINER (window), ttt);
6477   gtk_widget_show (ttt);
6478
6479   /* E gli aggancia il segnale "tictactoe" */
6480   gtk_signal_connect (GTK_OBJECT (ttt), "tictactoe",
6481                       GTK_SIGNAL_FUNC (win), NULL);
6482
6483   gtk_widget_show (window);
6484   
6485   gtk_main ();
6486   
6487   return 0;
6488 }
6489
6490 </verb></tscreen>
6491
6492
6493 <sect1> Creare un widget a partire da zero
6494
6495 <sect2> Introduzione
6496
6497 <p>
6498
6499 In questa sezione impareremo meglio come i widget si mostrano sullo schermo
6500 e interagiscono con gli eventi. Come esempio, creeremo
6501 un widget di quadrante analogico con un puntatore che l'utente 
6502 pu&ograve; trascinare per assegnare il valore.
6503
6504 <sect2> Mostrare un widget sullo schermo
6505
6506 <p>
6507 Ci sono alcuni passi che sono necessari nella visualizzazione sullo
6508 schermo. Dopo che il widget &egrave; stato creato con una chiamata a 
6509 <tt/WIDGETNAME_new()/, sono necessarie alcune altre funzioni:
6510
6511 <itemize>
6512 <item> <tt/WIDGETNAME_realize()/ &egrave; responsabile della creazione di 
6513 una finestra X per il widget se ne ha una.
6514 <item> <tt/WIDGETNAME_map()/ &egrave; invocata dopo che l'utente ha 
6515 chiamato <tt/gtk_widget_show()/. E' responsabile di vedere se il
6516 widget &egrave; attualmente disegnato sullo schermo (<em/mappato/). Per 
6517 una classe contenitore, essa deve anche creare chiamate alle 
6518 funzioni  <tt/map()/> per ogni widget figlio.
6519 <item> <tt/WIDGETNAME_draw()/ &egrave; invocata quando 
6520 <tt/gtk_widget_draw()/ viene chiamata per il widget o per uno dei suoi
6521 predecessori. Esso fa s&igrave; che l'attuale chiamata alla
6522 funzione di disegno del widget disegni il widget sullo schermo.
6523 Per la classe contenitore, questa funzione deve eseguire le
6524 chiamate alla funzioni <tt/gtk_widget_draw()/ di ogni suo widget
6525 figlio.
6526 <item> <tt/WIDGETNAME_expose()/ &egrave; un gestore per l'evento di esposizione
6527 per il widget. Esso crea le chiamate necessarie alle funzioni di disegno
6528 per disegnare la porzione che si &egrave; resa visibile. Per le classi 
6529 contenitore, questa funzione deve generare gli eventi di ``expose'' per 
6530 tutti i widget figli che non hanno una propria finestra (se essi hanno
6531 una loro finestra, sar&agrave; X che generer&agrave; i necessari eventi di expose).
6532 </itemize>
6533
6534 <p>
6535 Potete notare che le ultime due funzioni sono molto simili, ognuna &egrave;
6536 responsabile per il disegno del widget sullo schermo. Infatti molti
6537 tipi di widget non sanno relamente la differenza tra le due.
6538 La funzione di predefinita <tt/draw()/ nella classe widget, semplicemente
6539 genera un sintetico evento di ``expose'' per l'area da ridisegnare.
6540 Comunque, alcuni tipi di widget possono risparmiare tempo distinguendo
6541 le due funzioni. Per esempio, se un widget ha piu' finestre X, allora 
6542 visto che l'evento ``expose'' identifica solo la finestra esposta, 
6543 esso pu&ograve; ridisegnare solo la finestra interessata, cosa che non &egrave; 
6544 possibile per chiamate a <tt/draw()/.
6545
6546 <p>
6547 I widget contenitori, anche se essi non farebbero differenze,
6548 non possono semplicemente usare la funzione <tt/draw()/ perch&egrave; per i 
6549 loro widget figli la differenza potrebbere essere importante. Comunque, 
6550 sarebbe uno spreco duplicare il codice di disegno nelle due
6551 funzioni. La convenzione &egrave; che questi widget abbiano una funzione
6552 chiamata <tt/WIDGETNAME_paint()/ che disegna il widget, che &egrave; poi
6553 chiamata dalle funzioni <tt/draw()/ e <tt/expose()/
6554
6555 <p>
6556 Nell'approccio del nostro esempio, visto che il widget, ha 
6557 una sola finestra, possiamo utilizzare il modo piu' semplice
6558 ed usare la funzione predefinita <tt/draw()/ e implementare
6559 solamente la funzione <tt/expose()/.
6560
6561 <sect2> Le origini del widget Dial
6562
6563 <p>
6564 Come tutti gli animali terresti sono semplicemente varianti del primo
6565 amfibio, i widget Gtk tendono ad essere varianti di altri widget, precedentemente
6566 scritti. Cos&igrave;, anche se questa sezione &egrave; intitolata ``Creare
6567 un widget a partire da zero", il nostro widget inizia in realt&agrave; con il codice 
6568 sorgente del widget Range. Questo &egrave; stato preso come punto d'inizio
6569 perche' sarebbe carino se il nostro widget avesse la
6570 stessa interfaccia del widget Scale il quale &egrave; semplicemente una
6571 specializzazione del widget Range. Cos&igrave;, sebbene  il codice sorgente e' 
6572 presentato sotto in forma definitiva, non si deve pensare che sia stato
6573 scritto <em>deus ex machina</em> in questo modo. Se poi non avete familiarit&agrave;
6574 con il funzionamento del widget Scale dal punto di vista di chi scrive
6575 un'applicazione, potrebbe essere una buona idea guardare indietro prima 
6576 di continuare.
6577
6578 <sect2> Le basi
6579
6580 <p>
6581 Una parte del nostro widget potrebbe essere simile
6582 al widget Tictactoe. In primo luogo, abbiamo il file header:
6583
6584 <tscreen><verb>
6585 /* GTK - The GIMP Toolkit
6586  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
6587  *
6588  * This library is free software; you can redistribute it and/or
6589  * modify it under the terms of the GNU Library General Public
6590  * License as published by the Free Software Foundation; either
6591  * version 2 of the License, or (at your option) any later version.
6592  *
6593  * This library is distributed in the hope that it will be useful,
6594  * but WITHOUT ANY WARRANTY; without even the implied warranty of
6595  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
6596  * Library General Public License for more details.
6597  *
6598  * You should have received a copy of the GNU Library General Public
6599  * License along with this library; if not, write to the Free
6600  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
6601  */
6602
6603 #ifndef __GTK_DIAL_H__
6604 #define __GTK_DIAL_H__
6605
6606 #include <gdk/gdk.h>
6607 #include <gtk/gtkadjustment.h>
6608 #include <gtk/gtkwidget.h>
6609
6610
6611 #ifdef __cplusplus
6612 extern "C" {
6613 #endif /* __cplusplus */
6614
6615
6616 #define GTK_DIAL(obj)          GTK_CHECK_CAST (obj, gtk_dial_get_type (), GtkDial)
6617 #define GTK_DIAL_CLASS(klass)  GTK_CHECK_CLASS_CAST (klass, gtk_dial_get_type (), GtkDialClass)
6618 #define GTK_IS_DIAL(obj)       GTK_CHECK_TYPE (obj, gtk_dial_get_type ())
6619
6620
6621 typedef struct _GtkDial        GtkDial;
6622 typedef struct _GtkDialClass   GtkDialClass;
6623
6624 struct _GtkDial
6625 {
6626   GtkWidget widget;
6627
6628   /* Politica di update (GTK_UPDATE_[CONTINUOUS/DELAYED/DISCONTINUOUS]) */
6629   guint policy : 2;
6630
6631   /* Bottone correntemente premuto o 0 altrimenti */
6632   guint8 button;
6633
6634   /* Dimensione della componente Dial. */
6635   gint radius;
6636   gint pointer_width;
6637
6638   /* ID del timer di update, o 0 altrimenti */
6639   guint32 timer;
6640
6641   /* Angolo corrente. */
6642   gfloat angle;
6643
6644   /* Vecchi valori dell'aggiustamento cos&igrave; sappiamo quando 
6645    * qualcosa cambia */
6646   gfloat old_value;
6647   gfloat old_lower;
6648   gfloat old_upper;
6649
6650   /* L'oggetto adjustament che memorizza i dati per questo dial */
6651   GtkAdjustment *adjustment;
6652 };
6653
6654 struct _GtkDialClass
6655 {
6656   GtkWidgetClass parent_class;
6657 };
6658
6659
6660 GtkWidget*     gtk_dial_new                    (GtkAdjustment *adjustment);
6661 guint          gtk_dial_get_type               (void);
6662 GtkAdjustment* gtk_dial_get_adjustment         (GtkDial      *dial);
6663 void           gtk_dial_set_update_policy      (GtkDial      *dial,
6664                                                 GtkUpdateType  policy);
6665
6666 void           gtk_dial_set_adjustment         (GtkDial      *dial,
6667                                                 GtkAdjustment *adjustment);
6668 #ifdef __cplusplus
6669 }
6670 #endif /* __cplusplus */
6671
6672
6673 #endif /* __GTK_DIAL_H__ */
6674
6675 </verb></tscreen>
6676
6677 Essendoci pi&ugrave; cose da fare con questo widget, rispetto al precedente,
6678 abbiamo pi&ugrave; cambi nella struttura dati, ma le altre cose sono 
6679 abbastamza simili.
6680
6681 <p>
6682
6683 Dopo aver incluso i file di header e aver dichiarato alcune costanti,
6684 dobbiamo fornire alcune funzioni circa il widget e la sua
6685 inizializzazione.
6686
6687 <tscreen><verb>
6688 #include <math.h>
6689 #include <stdio.h>
6690 #include <gtk/gtkmain.h>
6691 #include <gtk/gtksignal.h>
6692
6693 #include "gtkdial.h"
6694
6695 #define SCROLL_DELAY_LENGTH  300
6696 #define DIAL_DEFAULT_SIZE 100
6697
6698 /* Dichiarazioni di funzioni successive */
6699
6700 [ omesse per salvare spazio ]
6701
6702 /* variabili locali. */
6703
6704 static GtkWidgetClass *parent_class = NULL;
6705
6706 guint
6707 gtk_dial_get_type ()
6708 {
6709   static guint dial_type = 0;
6710
6711   if (!dial_type)
6712     {
6713       GtkTypeInfo dial_info =
6714       {
6715         "GtkDial",
6716         sizeof (GtkDial),
6717         sizeof (GtkDialClass),
6718         (GtkClassInitFunc) gtk_dial_class_init,
6719         (GtkObjectInitFunc) gtk_dial_init,
6720         (GtkArgFunc) NULL,
6721       };
6722
6723       dial_type = gtk_type_unique (gtk_widget_get_type (), &amp;dial_info);
6724     }
6725
6726   return dial_type;
6727 }
6728
6729 static void
6730 gtk_dial_class_init (GtkDialClass *class)
6731 {
6732   GtkObjectClass *object_class;
6733   GtkWidgetClass *widget_class;
6734
6735   object_class = (GtkObjectClass*) class;
6736   widget_class = (GtkWidgetClass*) class;
6737
6738   parent_class = gtk_type_class (gtk_widget_get_type ());
6739
6740   object_class->destroy = gtk_dial_destroy;
6741
6742   widget_class->realize = gtk_dial_realize;
6743   widget_class->expose_event = gtk_dial_expose;
6744   widget_class->size_request = gtk_dial_size_request;
6745   widget_class->size_allocate = gtk_dial_size_allocate;
6746   widget_class->button_press_event = gtk_dial_button_press;
6747   widget_class->button_release_event = gtk_dial_button_release;
6748   widget_class->motion_notify_event = gtk_dial_motion_notify;
6749 }
6750
6751 static void
6752 gtk_dial_init (GtkDial *dial)
6753 {
6754   dial->button = 0;
6755   dial->policy = GTK_UPDATE_CONTINUOUS;
6756   dial->timer = 0;
6757   dial->radius = 0;
6758   dial->pointer_width = 0;
6759   dial->angle = 0.0;
6760   dial->old_value = 0.0;
6761   dial->old_lower = 0.0;
6762   dial->old_upper = 0.0;
6763   dial->adjustment = NULL;
6764 }
6765
6766 GtkWidget*
6767 gtk_dial_new (GtkAdjustment *adjustment)
6768 {
6769   GtkDial *dial;
6770
6771   dial = gtk_type_new (gtk_dial_get_type ());
6772
6773   if (!adjustment)
6774     adjustment = (GtkAdjustment*) gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
6775
6776   gtk_dial_set_adjustment (dial, adjustment);
6777
6778   return GTK_WIDGET (dial);
6779 }
6780
6781 static void
6782 gtk_dial_destroy (GtkObject *object)
6783 {
6784   GtkDial *dial;
6785
6786   g_return_if_fail (object != NULL);
6787   g_return_if_fail (GTK_IS_DIAL (object));
6788
6789   dial = GTK_DIAL (object);
6790
6791   if (dial->adjustment)
6792     gtk_object_unref (GTK_OBJECT (dial->adjustment));
6793
6794   if (GTK_OBJECT_CLASS (parent_class)->destroy)
6795     (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
6796 }
6797 </verb></tscreen>
6798
6799 Notate che questa funzione <tt/init()/ fa meno rispetto all'analoga del
6800 widget Tictactoe, essendo questo un widget non composto, e la 
6801 funzione <tt/new()/ fa di pi&ugrave;, essendoci un argomento. Inoltre, 
6802 notate che quando memorizziamo un puntatore all'oggetto Adjustment,
6803 incrementiamo il conteggio dei suoi riferimenti(e corrispondentemente 
6804 lo decrementato quando non lo usiamo pi&ugrave;) cos&igrave; che GTK pu&ograve; tener traccia di 
6805 quando &egrave; possibile distruggerlo senza causare guai.
6806
6807 <p>
6808 Inoltre, ci sono alcune funzioni per manipolare le opzioni del widget:
6809
6810 <tscreen><verb>
6811 GtkAdjustment*
6812 gtk_dial_get_adjustment (GtkDial *dial)
6813 {
6814   g_return_val_if_fail (dial != NULL, NULL);
6815   g_return_val_if_fail (GTK_IS_DIAL (dial), NULL);
6816
6817   return dial->adjustment;
6818 }
6819
6820 void
6821 gtk_dial_set_update_policy (GtkDial      *dial,
6822                              GtkUpdateType  policy)
6823 {
6824   g_return_if_fail (dial != NULL);
6825   g_return_if_fail (GTK_IS_DIAL (dial));
6826
6827   dial->policy = policy;
6828 }
6829
6830 void
6831 gtk_dial_set_adjustment (GtkDial      *dial,
6832                           GtkAdjustment *adjustment)
6833 {
6834   g_return_if_fail (dial != NULL);
6835   g_return_if_fail (GTK_IS_DIAL (dial));
6836
6837   if (dial->adjustment)
6838     {
6839       gtk_signal_disconnect_by_data (GTK_OBJECT (dial->adjustment), (gpointer) dial);
6840       gtk_object_unref (GTK_OBJECT (dial->adjustment));
6841     }
6842
6843   dial->adjustment = adjustment;
6844   gtk_object_ref (GTK_OBJECT (dial->adjustment));
6845
6846   gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
6847                       (GtkSignalFunc) gtk_dial_adjustment_changed,
6848                       (gpointer) dial);
6849   gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
6850                       (GtkSignalFunc) gtk_dial_adjustment_value_changed,
6851                       (gpointer) dial);
6852
6853   dial->old_value = adjustment->value;
6854   dial->old_lower = adjustment->lower;
6855   dial->old_upper = adjustment->upper;
6856
6857   gtk_dial_update (dial);
6858 }
6859 </verb></tscreen>
6860
6861 <sect2> <tt/gtk_dial_realize()/
6862
6863 <p>
6864 Abbiamo ora raggiunto alcuni nuovi tipi di funzione. In primo luogo,
6865 abbiamo una funzione che crea la finestra di X. Noterete che viene
6866 passata alla funzione <tt/gdk_window_new()/ una maschera che 
6867 specifica quali campi della struttura GdkWindowAttr non sono vuoti 
6868 (ai rimanenti campi pu&ograve; essere dato il valore predefinito). Anche 
6869 il modo con cui la maschera degli eventi del widget  creata non &egrave;
6870 complicato. Chiameremo <tt/gtk_widget_get_events()/ per sapere la 
6871 maschera degli eventi che l'utente ha specificato per questo widget
6872 (con <tt/gtk_widget_set_events()/) e aggiungeremo gli eventi che ci possono 
6873 interessare.
6874
6875 <p>
6876 Dopo aver creato la finestra, settiamo lo stile e lo sfondo,
6877 e creiamo un puntatore al widget nel campo dei dati utente (user data)
6878 del GdkWindow. Quest'ultimo passo permette a GTK di mandare gli 
6879 eventi della finestra al widget corretto.
6880
6881 <tscreen><verb>
6882 static void
6883 gtk_dial_realize (GtkWidget *widget)
6884 {
6885   GtkDial *dial;
6886   GdkWindowAttr attributes;
6887   gint attributes_mask;
6888
6889   g_return_if_fail (widget != NULL);
6890   g_return_if_fail (GTK_IS_DIAL (widget));
6891
6892   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
6893   dial = GTK_DIAL (widget);
6894
6895   attributes.x = widget->allocation.x;
6896   attributes.y = widget->allocation.y;
6897   attributes.width = widget->allocation.width;
6898   attributes.height = widget->allocation.height;
6899   attributes.wclass = GDK_INPUT_OUTPUT;
6900   attributes.window_type = GDK_WINDOW_CHILD;
6901   attributes.event_mask = gtk_widget_get_events (widget) | 
6902     GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | 
6903     GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK |
6904     GDK_POINTER_MOTION_HINT_MASK;
6905   attributes.visual = gtk_widget_get_visual (widget);
6906   attributes.colormap = gtk_widget_get_colormap (widget);
6907
6908   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
6909   widget->window = gdk_window_new (widget->parent->window, &amp;attributes, attributes_mask);
6910
6911   widget->style = gtk_style_attach (widget->style, widget->window);
6912
6913   gdk_window_set_user_data (widget->window, widget);
6914
6915   gtk_style_set_background (widget->style, widget->window, GTK_STATE_ACTIVE);
6916 }
6917 </verb></tscreen>
6918
6919 <sect2> Negoziazione della dimensione
6920
6921 <p>
6922 Prima di visualizzare per la prima volta la finestra, e  se il 
6923 layout della finestra cambia, GTK chiede ad ogni widget, incluso nella
6924 finestra, la propria dimensione. Questa richiesta &egrave; fatta dalla
6925 funzione  <tt/gtk_dial_size_request()/. Non essendo il nostro widget 
6926 un contenitore, e non avendo dei veri limiti per la propria
6927 dimensione, restituiamo semplicemnte un valore ragionevole.
6928
6929 <tscreen><verb>
6930 static void 
6931 gtk_dial_size_request (GtkWidget      *widget,
6932                        GtkRequisition *requisition)
6933 {
6934   requisition->width = DIAL_DEFAULT_SIZE;
6935   requisition->height = DIAL_DEFAULT_SIZE;
6936 }
6937 </verb></tscreen>
6938
6939 <p>
6940 Dopo che tutti i widget hanno restituito una dimensione ideale, viene 
6941 calcolata la disposizione della finestra  e ad ogni widget figlio &egrave;
6942 notificata la propria dimensione attuale <!--ndMichel : che pu&ograve; essere diversa
6943 da quella restitutita con la funzione sopra -->. Usualmente, questo sar&agrave; 
6944 almeno quanto richiesto, ma occasionalmente pu&ograve; essere pi&ugrave; piccolo. 
6945 La notifica della dimensione  viene fatta dalla funzione
6946  <tt/gtk_dial_size_allocate()/. Notate che questa funzione &egrave; utilizzata
6947 anche quando la finestra X del widget &egrave; spostata o modificata come 
6948 dimensione.
6949
6950 <tscreen><verb>
6951 static void
6952 gtk_dial_size_allocate (GtkWidget     *widget,
6953                         GtkAllocation *allocation)
6954 {
6955   GtkDial *dial;
6956
6957   g_return_if_fail (widget != NULL);
6958   g_return_if_fail (GTK_IS_DIAL (widget));
6959   g_return_if_fail (allocation != NULL);
6960
6961   widget->allocation = *allocation;
6962   if (GTK_WIDGET_REALIZED (widget))
6963     {
6964       dial = GTK_DIAL (widget);
6965
6966       gdk_window_move_resize (widget->window,
6967                               allocation->x, allocation->y,
6968                               allocation->width, allocation->height);
6969
6970       dial->radius = MAX(allocation->width,allocation->height) * 0.45;
6971       dial->pointer_width = dial->radius / 5;
6972     }
6973 }
6974 </verb></tscreen>.
6975
6976 <sect2> <tt/gtk_dial_expose()/
6977
6978 <p>
6979 Come menzionato sopra, tutto il lavoro di questo widget viene fatto nella
6980 gestione dell'evento ``expose''. Non c'&egrave; molto da notare su questo eccetto
6981 l'uso della funzione <tt/gtk_draw_polygon/ per disegnare il 
6982 puntatore con un'ombreggiatura a tre dimensioni in accordo con il colore
6983 memorizzato nello stile del wiget.
6984
6985 <tscreen><verb>
6986 static gint
6987 gtk_dial_expose (GtkWidget      *widget,
6988                  GdkEventExpose *event)
6989 {
6990   GtkDial *dial;
6991   GdkPoint points[3];
6992   gdouble s,c;
6993   gdouble theta;
6994   gint xc, yc;
6995   gint tick_length;
6996   gint i;
6997
6998   g_return_val_if_fail (widget != NULL, FALSE);
6999   g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
7000   g_return_val_if_fail (event != NULL, FALSE);
7001
7002   if (event->count > 0)
7003     return FALSE;
7004   
7005   dial = GTK_DIAL (widget);
7006
7007   gdk_window_clear_area (widget->window,
7008                          0, 0,
7009                          widget->allocation.width,
7010                          widget->allocation.height);
7011
7012   xc = widget->allocation.width/2;
7013   yc = widget->allocation.height/2;
7014
7015   /* Draw ticks */
7016
7017   for (i=0; i<25; i++)
7018     {
7019       theta = (i*M_PI/18. - M_PI/6.);
7020       s = sin(theta);
7021       c = cos(theta);
7022
7023       tick_length = (i%6 == 0) ? dial->pointer_width : dial->pointer_width/2;
7024       
7025       gdk_draw_line (widget->window,
7026                      widget->style->fg_gc[widget->state],
7027                      xc + c*(dial->radius - tick_length),
7028                      yc - s*(dial->radius - tick_length),
7029                      xc + c*dial->radius,
7030                      yc - s*dial->radius);
7031     }
7032
7033   /* Draw pointer */
7034
7035   s = sin(dial->angle);
7036   c = cos(dial->angle);
7037
7038
7039   points[0].x = xc + s*dial->pointer_width/2;
7040   points[0].y = yc + c*dial->pointer_width/2;
7041   points[1].x = xc + c*dial->radius;
7042   points[1].y = yc - s*dial->radius;
7043   points[2].x = xc - s*dial->pointer_width/2;
7044   points[2].y = yc - c*dial->pointer_width/2;
7045
7046   gtk_draw_polygon (widget->style,
7047                     widget->window,
7048                     GTK_STATE_NORMAL,
7049                     GTK_SHADOW_OUT,
7050                     points, 3,
7051                     TRUE);
7052   
7053   return FALSE;
7054 }
7055 </verb></tscreen>
7056
7057 <sect2> Gestore degli eventi
7058
7059 <p>
7060
7061 Il resto del codice del widget manipola vari tipi di eventi, e non
7062 &egrave; differente da quello che pu&ograve; essere trovato in molte applicazione
7063 GTK. Due tipi di eventi possono verificarsi: l'utente pu&ograve; 
7064 clickare sul widget con il mouse e trascinare per muovere il puntatore, 
7065 o il valore dell'oggetto Adjustmente pu&ograve; cambiare a causa di alcune
7066 circostanze esterne.
7067
7068 <p>
7069 Quando l'utente clicka sul widget, noi vediamo se la pressione
7070 era veramente vicina al puntatore, e se cos&igrave;, memorizziamo il bottone
7071 premuto dall'utente con il campo <tt/button/ della struttura del
7072 widget, e prendiamo tutti gli eventi del mouse con una chiamata alla
7073 funzione <tt/gtk_grab_add()/. Successivi movimenti del mouse causano il 
7074 ricalcolo dei valori di controllo (fatto dalla funzione 
7075 <tt/gtk_dial_update_mouse/). Dipendentemente dalla politica che abbiamo
7076 stabilito, gli eventi ``value_changed'' possono essere  generati
7077 istantaneamente (<tt/GTK_UPDATE_CONTINUOUS/), dopo un certo tempo aggiunto
7078 con la funzione <tt/gtk_timeout_add()/ (<tt/GTK_UPDATE_DELAYED/), o
7079 solamente quando il bottone del mouse e' rilasciato 
7080 (<tt/GTK_UPDATE_DISCONTINUOUS/).
7081
7082 <tscreen><verb>
7083 static gint
7084 gtk_dial_button_press (GtkWidget      *widget,
7085                        GdkEventButton *event)
7086 {
7087   GtkDial *dial;
7088   gint dx, dy;
7089   double s, c;
7090   double d_parallel;
7091   double d_perpendicular;
7092
7093   g_return_val_if_fail (widget != NULL, FALSE);
7094   g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
7095   g_return_val_if_fail (event != NULL, FALSE);
7096
7097   dial = GTK_DIAL (widget);
7098
7099   /* Determina se il bottone premuto era dentro la regione del puntatore:
7100      lo facciamo calcolando la distanza parallela e 
7101      perpendicolare dal punto dove il bottone del mouse e' stato premuto
7102      alla linea passante per il puntatore. */
7103   
7104   dx = event->x - widget->allocation.width / 2;
7105   dy = widget->allocation.height / 2 - event->y;
7106   
7107   s = sin(dial->angle);
7108   c = cos(dial->angle);
7109   
7110   d_parallel = s*dy + c*dx;
7111   d_perpendicular = fabs(s*dx - c*dy);
7112   
7113   if (!dial->button &&
7114       (d_perpendicular < dial->pointer_width/2) &&
7115       (d_parallel > - dial->pointer_width))
7116     {
7117       gtk_grab_add (widget);
7118
7119       dial->button = event->button;
7120
7121       gtk_dial_update_mouse (dial, event->x, event->y);
7122     }
7123
7124   return FALSE;
7125 }
7126
7127 static gint
7128 gtk_dial_button_release (GtkWidget      *widget,
7129                           GdkEventButton *event)
7130 {
7131   GtkDial *dial;
7132
7133   g_return_val_if_fail (widget != NULL, FALSE);
7134   g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
7135   g_return_val_if_fail (event != NULL, FALSE);
7136
7137   dial = GTK_DIAL (widget);
7138
7139   if (dial->button == event->button)
7140     {
7141       gtk_grab_remove (widget);
7142
7143       dial->button = 0;
7144
7145       if (dial->policy == GTK_UPDATE_DELAYED)
7146         gtk_timeout_remove (dial->timer);
7147       
7148       if ((dial->policy != GTK_UPDATE_CONTINUOUS) &&
7149           (dial->old_value != dial->adjustment->value))
7150         gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
7151     }
7152
7153   return FALSE;
7154 }
7155
7156 static gint
7157 gtk_dial_motion_notify (GtkWidget      *widget,
7158                          GdkEventMotion *event)
7159 {
7160   GtkDial *dial;
7161   GdkModifierType mods;
7162   gint x, y, mask;
7163
7164   g_return_val_if_fail (widget != NULL, FALSE);
7165   g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
7166   g_return_val_if_fail (event != NULL, FALSE);
7167
7168   dial = GTK_DIAL (widget);
7169
7170   if (dial->button != 0)
7171     {
7172       x = event->x;
7173       y = event->y;
7174
7175       if (event->is_hint || (event->window != widget->window))
7176         gdk_window_get_pointer (widget->window, &amp;x, &amp;y, &amp;mods);
7177
7178       switch (dial->button)
7179         {
7180         case 1:
7181           mask = GDK_BUTTON1_MASK;
7182           break;
7183         case 2:
7184           mask = GDK_BUTTON2_MASK;
7185           break;
7186         case 3:
7187           mask = GDK_BUTTON3_MASK;
7188           break;
7189         default:
7190           mask = 0;
7191           break;
7192         }
7193
7194       if (mods & mask)
7195         gtk_dial_update_mouse (dial, x,y);
7196     }
7197
7198   return FALSE;
7199 }
7200
7201 static gint
7202 gtk_dial_timer (GtkDial *dial)
7203 {
7204   g_return_val_if_fail (dial != NULL, FALSE);
7205   g_return_val_if_fail (GTK_IS_DIAL (dial), FALSE);
7206
7207   if (dial->policy == GTK_UPDATE_DELAYED)
7208     gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
7209
7210   return FALSE;
7211 }
7212
7213 static void
7214 gtk_dial_update_mouse (GtkDial *dial, gint x, gint y)
7215 {
7216   gint xc, yc;
7217   gfloat old_value;
7218
7219   g_return_if_fail (dial != NULL);
7220   g_return_if_fail (GTK_IS_DIAL (dial));
7221
7222   xc = GTK_WIDGET(dial)->allocation.width / 2;
7223   yc = GTK_WIDGET(dial)->allocation.height / 2;
7224
7225   old_value = dial->adjustment->value;
7226   dial->angle = atan2(yc-y, x-xc);
7227
7228   if (dial->angle < -M_PI/2.)
7229     dial->angle += 2*M_PI;
7230
7231   if (dial->angle < -M_PI/6)
7232     dial->angle = -M_PI/6;
7233
7234   if (dial->angle > 7.*M_PI/6.)
7235     dial->angle = 7.*M_PI/6.;
7236
7237   dial->adjustment->value = dial->adjustment->lower + (7.*M_PI/6 - dial->angle) *
7238     (dial->adjustment->upper - dial->adjustment->lower) / (4.*M_PI/3.);
7239
7240   if (dial->adjustment->value != old_value)
7241     {
7242       if (dial->policy == GTK_UPDATE_CONTINUOUS)
7243         {
7244           gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
7245         }
7246       else
7247         {
7248           gtk_widget_draw (GTK_WIDGET(dial), NULL);
7249
7250           if (dial->policy == GTK_UPDATE_DELAYED)
7251             {
7252               if (dial->timer)
7253                 gtk_timeout_remove (dial->timer);
7254
7255               dial->timer = gtk_timeout_add (SCROLL_DELAY_LENGTH,
7256                                              (GtkFunction) gtk_dial_timer,
7257                                              (gpointer) dial);
7258             }
7259         }
7260     }
7261 }
7262 </verb></tscreen>
7263
7264 <p>
7265 Cambiamenti esterni all'Adjustment sono comunicati al nostro widget
7266 dai segnali ``changed'' e ``value_changed''. Il gestore per 
7267 queste funzioni chiama  <tt/gtk_dial_update()/ per validare gli
7268 argomenti, calcolare il nuovo angolo del puntatore e ridisegnare il
7269 widget (chiamando <tt/gtk_widget_draw()/).
7270
7271 <tscreen><verb>
7272 static void
7273 gtk_dial_update (GtkDial *dial)
7274 {
7275   gfloat new_value;
7276   
7277   g_return_if_fail (dial != NULL);
7278   g_return_if_fail (GTK_IS_DIAL (dial));
7279
7280   new_value = dial->adjustment->value;
7281   
7282   if (new_value < dial->adjustment->lower)
7283     new_value = dial->adjustment->lower;
7284
7285   if (new_value > dial->adjustment->upper)
7286     new_value = dial->adjustment->upper;
7287
7288   if (new_value != dial->adjustment->value)
7289     {
7290       dial->adjustment->value = new_value;
7291       gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
7292     }
7293
7294   dial->angle = 7.*M_PI/6. - (new_value - dial->adjustment->lower) * 4.*M_PI/3. /
7295     (dial->adjustment->upper - dial->adjustment->lower);
7296
7297   gtk_widget_draw (GTK_WIDGET(dial), NULL);
7298 }
7299
7300 static void
7301 gtk_dial_adjustment_changed (GtkAdjustment *adjustment,
7302                               gpointer       data)
7303 {
7304   GtkDial *dial;
7305
7306   g_return_if_fail (adjustment != NULL);
7307   g_return_if_fail (data != NULL);
7308
7309   dial = GTK_DIAL (data);
7310
7311   if ((dial->old_value != adjustment->value) ||
7312       (dial->old_lower != adjustment->lower) ||
7313       (dial->old_upper != adjustment->upper))
7314     {
7315       gtk_dial_update (dial);
7316
7317       dial->old_value = adjustment->value;
7318       dial->old_lower = adjustment->lower;
7319       dial->old_upper = adjustment->upper;
7320     }
7321 }
7322
7323 static void
7324 gtk_dial_adjustment_value_changed (GtkAdjustment *adjustment,
7325                                     gpointer       data)
7326 {
7327   GtkDial *dial;
7328
7329   g_return_if_fail (adjustment != NULL);
7330   g_return_if_fail (data != NULL);
7331
7332   dial = GTK_DIAL (data);
7333
7334   if (dial->old_value != adjustment->value)
7335     {
7336       gtk_dial_update (dial);
7337
7338       dial->old_value = adjustment->value;
7339     }
7340 }
7341 </verb></tscreen>
7342
7343 <sect2> Possibili Miglioramenti
7344
7345 <p>
7346
7347 Il widget Dial, da come l'abbiamo costruito, &egrave; lungo circa 670 linee
7348 di codice C. Anche se questo potrebbe sembrare un po' troppo, abbiamo
7349 realmente fatto un bel po' con quel tanto di codice, specialmente 
7350 considerando che molta della lunghezza &egrave; costituita da file header e
7351 commmenti. Comunque ci sono alcuni miglioramenti che potrebbero essere
7352 fatti a questo widget:
7353
7354 <itemize>
7355 <item> Se tu provate questo widget, troverete che ci sono alcuni lampeggiamenti
7356 quando il puntatore viene trascinato in giro. Questo 
7357 perch&egrave; l'intero widget &egrave; cancellato ogni volta che il 
7358 puntatore viene mosso, prima di essere ridisegnato. Spesso, il modo migliore
7359 per gestire questo tipo di problema &egrave; il disegnare il tutto su una 
7360 pixmap non visibile, poi copiare il risultato finale sullo schermo 
7361 in una passata sola (il widget ProgressBar viene disegnato in questo
7362 modo).
7363
7364 <item> L'utente potrebbe essere abilitato ad usare le frecce su e giu per
7365 incrementare e diminuire il valore.
7366
7367 <item> Potrebbe essere carino se il widget avesse i bottoni per 
7368 incrementare e decrementare il valore di step. Anche se potrebbe essere
7369 possibile usare dei widget Bottone incorporati per questo, possiamo anche
7370 far s&igrave; che il bottone sia auto-ripentente quando premuto, come le frecce
7371 in una barra di scorrimento. Molto del codice per implementare questo tipo di 
7372 comportamento pu&ograve; essere trovato nel widget GtkRange.
7373
7374 <item> il widget Dial potrebbe essere fatto/creato dentro un widget 
7375 contenitore con un singolo widget figlio posizionato all'inizio tra i 
7376 2 bottoni menzionati prima. L'utente potrebbe poi aggiungere o una etichetta
7377 o un widget ``entry'' per mostrare il valore corrente del dial.
7378
7379 </itemize>
7380
7381 <sect1> Impararne di pi&ugrave;
7382
7383 <p> 
7384 Fin qui abbiamo esposto solo una piccola parte di tutto quello che serve
7385 per creare un widget. Se volete davvero  scrivere un vostro widget, la
7386 miglior risorsa di esempi &egrave; lo stesso codice sorgente GTK. Chiedete a voi
7387 stessi alcune cose su come deve essere il widget che volete scrivere: &egrave;
7388 un widget contenitore? dovr&agrave; avere una propria finestra? &egrave; una modifica di 
7389 un widget precedente? Trovate poi un widget simile e iniziate a fargli 
7390 delle modifiche.
7391 Buone Fortuna.
7392
7393
7394 <sect>Scribble, Un semplice esempio di Programma di Disegno
7395
7396 <sect1> Panoramica
7397
7398 <p>
7399 In questa sezione, creeremo un semplice programma di disegno. Durante
7400 questo processo, esamineremo come gestire gli eventi generati dal mouse,
7401 come disegnare all'interno di una finestra e come disegnare in modo migliore
7402 usando una pixmap di supporto. Dopo averlo creato, lo amplieremo aggiungendo
7403 il supporto per i dispositivi XInput, per esempio le tavolette grafiche.
7404 Il GTK fornisce delle routine di supporto grazie alle quali risulta  piuttosto
7405 semplice ottenere informazioni estese, come la pressione o l'inclinazione.
7406
7407 <sect1> Gestione degli Eventi
7408
7409 <p>
7410 I segnali di GTK che abbiamo discusso finora si riferivano ad azioni di
7411 alto livello, ad esempio la selezione di un elemento di un men&ugrave;. Per&ograve;, a volte
7412 &egrave; utile sapere qualcosa su cose che si svolgono a livello pi&ugrave; basso livello,
7413 come possono essere il movimento del mouse o la pressione di un tasto.
7414 Ci sono segnali di GTK anche per questi <em>eventi</em> di basso livello.
7415 I gestori di questo tipo di segnali hanno un parametro caratteristico in pi&ugrave;,
7416 che &egrave; il puntatore ad una struttura che contiene informazioni riguardo
7417 all'evento. Per esempio, ai gestori di eventi che riguardano dei movimenti,
7418 si passa un puntatore ad una struttura GdkEventMotion, che &egrave; fatta (in parte)
7419 cos&igrave;:
7420
7421 <tscreen><verb>
7422 struct _GdkEventMotion
7423 {
7424   GdkEventType type;
7425   GdkWindow *window;
7426   guint32 time;
7427   gdouble x;
7428   gdouble y;
7429   ...
7430   guint state;
7431   ...
7432 };
7433 </verb></tscreen>
7434
7435 <tt/type/ avr&agrave; il valore del tipo di evento, in questo caso 
7436 <tt/GDK_MOTION_NOTIFY/, <tt/window/ rappresenta la finestra in cui l'evento
7437 si &egrave; verificato. <tt/x/ e <tt/y/ forniscono le coordinate dell'evento e
7438 <tt/state/ specifica lo stato dei modificatori nel momento in cui l'evento
7439 si &egrave; verificato (cio&egrave;, specifica quali tasti modificatori e tasti del mouse
7440 erano premuti in quel momento). E' un OR bit per bit dei seguenti valori:
7441
7442 <tscreen><verb>
7443 GDK_SHIFT_MASK  
7444 GDK_LOCK_MASK   
7445 GDK_CONTROL_MASK
7446 GDK_MOD1_MASK   
7447 GDK_MOD2_MASK   
7448 GDK_MOD3_MASK   
7449 GDK_MOD4_MASK   
7450 GDK_MOD5_MASK   
7451 GDK_BUTTON1_MASK
7452 GDK_BUTTON2_MASK
7453 GDK_BUTTON3_MASK
7454 GDK_BUTTON4_MASK
7455 GDK_BUTTON5_MASK
7456 </verb></tscreen>
7457
7458 <p>
7459 Come succede per gli altri segnali, per determinare cosa deve accadere in
7460 corrispondenza di un evento, si chiama <tt>gtk_signal_connect()</tt>. Ma
7461 &egrave; anche necessario far s&igrave; che GTK sappia di quali eventi vogliamo essere
7462 informati. A questo fine, chiamiamo la funzione:
7463
7464 <tscreen><verb>
7465 void  gtk_widget_set_events (GtkWidget *widget, gint events);
7466 </verb></tscreen>
7467
7468 Il secondo campo specifica gli eventi che ci interessano. Si tratta dell'OR
7469 bit per bit delle costanti che identificano i diversi tipi di eventi. La lista
7470 dei tipi di eventi &egrave; la seguente:
7471
7472 <tscreen><verb>
7473 GDK_EXPOSURE_MASK
7474 GDK_POINTER_MOTION_MASK
7475 GDK_POINTER_MOTION_HINT_MASK
7476 GDK_BUTTON_MOTION_MASK     
7477 GDK_BUTTON1_MOTION_MASK    
7478 GDK_BUTTON2_MOTION_MASK    
7479 GDK_BUTTON3_MOTION_MASK    
7480 GDK_BUTTON_PRESS_MASK      
7481 GDK_BUTTON_RELEASE_MASK    
7482 GDK_KEY_PRESS_MASK         
7483 GDK_KEY_RELEASE_MASK       
7484 GDK_ENTER_NOTIFY_MASK      
7485 GDK_LEAVE_NOTIFY_MASK      
7486 GDK_FOCUS_CHANGE_MASK      
7487 GDK_STRUCTURE_MASK         
7488 GDK_PROPERTY_CHANGE_MASK   
7489 GDK_PROXIMITY_IN_MASK      
7490 GDK_PROXIMITY_OUT_MASK     
7491 </verb></tscreen>
7492
7493 Per chiamare <tt/gtk_widget_set_events()/, si devono fare alcune osservazioni
7494 sottili. In primo luogo, la si deve chiamare prima che sia stata creata la
7495 finestra X per il widget GTK. In pratica, ci&ograve; significa che la si deve
7496 chiamare subito dopo aver creato il widget. In secondo luogo, il widget
7497 deve avere una finestra X associata. Molti widget, per ragioni di
7498 efficienza, non hanno una propria finetra, e vengono mostrati nella
7499 finestra madre. Questi widget sono:
7500
7501 <tscreen><verb>
7502 GtkAlignment
7503 GtkArrow
7504 GtkBin
7505 GtkBox
7506 GtkImage
7507 GtkItem
7508 GtkLabel
7509 GtkPaned
7510 GtkPixmap
7511 GtkScrolledWindow
7512 GtkSeparator
7513 GtkTable
7514 GtkViewport
7515 GtkAspectFrame
7516 GtkFrame
7517 GtkVPaned
7518 GtkHPaned
7519 GtkVBox
7520 GtkHBox
7521 GtkVSeparator
7522 GtkHSeparator
7523 </verb></tscreen>
7524
7525 Per catturare degli eventi per questo tipo di widget, si deve fare uso 
7526 del widget EventBox. Si veda a questo proposito la sezione su
7527 <ref id="sec_The_EventBox_Widget" name="The EventBox Widget">.
7528
7529 <p>
7530 Per il nostro programma di disegno, vogliamo sapere quando il pulsante del
7531 mouse &egrave; premuto e quando viene mosso, quindi specificheremo
7532 <tt/GDK_POINTER_MOTION_MASK/ e <tt/GDK_BUTTON_PRESS_MASK/. Vogliamo anche
7533 essere informati su quando &egrave; necessario ridisegnare la nostra finestra,
7534 quindi specifichiamo <tt/GDK_EXPOSURE_MASK/. Anche se vogliamo essere
7535 avvertiti con un evento ``Configure'' se la dimensione della nostra finestra
7536 cambia, non &egrave; necessario specificare il flag <tt/GDK_STRUCTURE_MASK/, dal
7537 momento che questo viene specificato automaticamente per tutte le finestre.
7538
7539 <p>
7540 Risulta, conunque, che specificando semplicemente <tt/GDK_POINTER_MOTION_MASK/
7541 si crea un problema. Ci&ograve; infatti fa s&igrave; che il server aggiunga nella coda un
7542 un nuovo evento di movimento ogni volta che l'utente muovoe il mouse. Immaginate
7543 che ci vogliano 0.1 secondi per gestire uno di questi eventi, e che il server
7544 X metta in coda un nuovo evento ogni 0.05 secondi. Rimarremo ben presto indietro
7545 rispetto al disegno dell'utente. Se l'utente disegna per 5 secondi, ci metteremmo
7546 altri 5 secondi prima di finire dopo che l'utente ha rilasciato il pulsante del
7547 mouse! Vorremmo quindi che venga notificato un solo evento di movimento per
7548 ogni evento che processiamo. Il modo per farlo &egrave; di specificare 
7549 <tt/GDK_POINTER_MOTION_HINT_MASK/. 
7550
7551 <p>
7552 Quando specifichiamo <tt/GDK_POINTER_MOTION_HINT_MASK/, il server ci notifica
7553 un evento di movimento la prima volta che il puntatore si muove dopo essere
7554 entrato nella nostra finestra, oppure dopo ogni rilascio di un pulsante del
7555 mouse. Gli altri eventi di movimento verranno soppressi finch&eacute; non richiediamo
7556 esplicitamente la posizione del puntatore con la funzione:
7557
7558 <tscreen><verb>
7559 GdkWindow*    gdk_window_get_pointer     (GdkWindow       *window,
7560                                           gint            *x,
7561                                           gint            *y,
7562                                           GdkModifierType *mask);
7563 </verb></tscreen>
7564
7565 (c'&egrave; anche un'altra funzione, <tt>gtk_widget_get_pointer()</tt>, che ha
7566 un'interfaccia pi&ugrave; semplice, ma che non risulta molto utile dal momento
7567 che restituisce solo la posizione del puntatore, senza dettagli sullo
7568 sato dei pulsanti.)
7569
7570 <p>
7571 Quindi, il codice per assegnare gli eventi per la nostra finestra, avr&agrave; l'aspetto:
7572
7573 <tscreen><verb>
7574   gtk_signal_connect (GTK_OBJECT (drawing_area), "expose_event",
7575                       (GtkSignalFunc) expose_event, NULL);
7576   gtk_signal_connect (GTK_OBJECT(drawing_area),"configure_event",
7577                       (GtkSignalFunc) configure_event, NULL);
7578   gtk_signal_connect (GTK_OBJECT (drawing_area), "motion_notify_event",
7579                       (GtkSignalFunc) motion_notify_event, NULL);
7580   gtk_signal_connect (GTK_OBJECT (drawing_area), "button_press_event",
7581                       (GtkSignalFunc) button_press_event, NULL);
7582
7583   gtk_widget_set_events (drawing_area, GDK_EXPOSURE_MASK
7584                          | GDK_LEAVE_NOTIFY_MASK
7585                          | GDK_BUTTON_PRESS_MASK
7586                          | GDK_POINTER_MOTION_MASK
7587                          | GDK_POINTER_MOTION_HINT_MASK);
7588 </verb></tscreen>
7589
7590 Teniamo per dopo i gestori di  ``expose_event'' e  ``configure_event''. Quelli di
7591 ``motion_notify_event'' e ``button_press_event'' sono piuttosto semplici: 
7592
7593 <tscreen><verb>
7594 static gint
7595 button_press_event (GtkWidget *widget, GdkEventButton *event)
7596 {
7597   if (event->button == 1 &amp;&amp; pixmap != NULL)
7598       draw_brush (widget, event->x, event->y);
7599
7600   return TRUE;
7601 }
7602
7603 static gint
7604 motion_notify_event (GtkWidget *widget, GdkEventMotion *event)
7605 {
7606   int x, y;
7607   GdkModifierType state;
7608
7609   if (event->is_hint)
7610     gdk_window_get_pointer (event->window, &amp;x, &amp;y, &amp;state);
7611   else
7612     {
7613       x = event->x;
7614       y = event->y;
7615       state = event->state;
7616     }
7617     
7618   if (state &amp; GDK_BUTTON1_MASK &amp;&amp; pixmap != NULL)
7619     draw_brush (widget, x, y);
7620   
7621   return TRUE;
7622 }
7623 </verb></tscreen>
7624
7625
7626 <sect1> Il widget Area di Disegno (DrawingArea) e il procedimento per Disegnare
7627
7628 <p>
7629 Vediamo ora il procedimento per disegnare sullo schermo. Il
7630 widget da usare &egrave; l'Area di Disegno (DrawingArea). Essenzialmente si
7631 tratta di una finestra X e nient'altro. E' una tela bianca su cui possimo
7632 disegnare tutto quello che vogliamo. Per crearne una usiamo la chiamata:
7633
7634 <tscreen><verb>
7635 GtkWidget* gtk_drawing_area_new        (void);
7636 </verb></tscreen>
7637
7638 Per specificare una dimensione predefinita, si puo fare:
7639
7640 <tscreen><verb>
7641 void       gtk_drawing_area_size       (GtkDrawingArea      *darea,
7642                                         gint                 width,
7643                                         gint                 height);
7644 </verb></tscreen>
7645
7646 Come &egrave; vero per tutti i widget, si pu&ograve; modificare questa dimensione
7647 predefinita, tramite la chamata a <tt>gtk_widget_set_usize()</tt>, e
7648 questa a sua volta pu&ograve; essere modificata dall'utente ridimensionando
7649 manualmente la finestra che contiene l'area di disegno.
7650
7651 <p>
7652 Si deve notare che nel momento in cui creiamo un widget DrawingArea, siamo
7653 <em>completamente</em> responsabili di disegnarne il contenuto. Se ad 
7654 esempio la nostra finestra viene prima nascosta e poi dinuovo portata in
7655 primo piano, otteniamo un evento di ``esposizione'' e doppiamo ridisegnare
7656 ci&ograve; che era stato precedente nascosto.
7657
7658 <p>
7659 Dover ricordare tutto quello che era disegnato sulla finestra in modo da
7660 poterlo ridisegnare successivamente, pu&ograve; essere, come minimo, noioso.
7661 In pi&ugrave;, pu&ograve; essere spiacevole dal punto di vista visivo, se delle porzioni
7662 dello schermo vengono prima cancellate e poi ridisegnate passo per passo.
7663 La soluzione per questo problema &egrave; di usare una <em>pixmap di supporto</em>.
7664 Invece di disegnare direttamente sullo schermo, disegnamo su un'iimagine
7665 conservata nella memoria del server ma che non viene mostrata; quindi, quando
7666 l'immagine cambia o ne vengono mostrate nuove porzioni, copiamo sullo schermo
7667 le parti corrispondenti.
7668
7669 <p>
7670 Per creare una ppixmap fuori dallo schermo, usiamo la funzione:
7671
7672 <tscreen><verb>
7673 GdkPixmap* gdk_pixmap_new               (GdkWindow  *window,
7674                                          gint        width,
7675                                          gint        height,
7676                                          gint        depth);
7677 </verb></tscreen>
7678
7679 Il parametro <tt>window</tt>specifica una finestra GDK dalla quale questa
7680 pixmap prende alcune delle sue propriet&agrave;. <tt>width</tt> e <tt>height</tt>
7681 specificano le dimensioni della pixmap.  <tt>depth</tt> specifica la 
7682 <em>profondit&agrave; di colore</em>, cio&egrave; il numero di bit per ogni pixel, per
7683 la nuova pixmap. Se alla profondit&agrave; &egrave; assegnato il valore <tt>-1</tt>, questa
7684 verr&agrave; posta identica a quella di <tt>window</tt>.
7685
7686 <p>
7687 Creiamo la pixmap all'interno del gestore di ``configure_event''. Questo evento
7688 &egrave; generato ogni volta che la finestra cambia di dimensione, compreso il
7689 momento in cui viene creata per la prima volta.
7690
7691 <tscreen><verb>
7692 /* Pixmap di supporto per l'area di disegno */
7693 static GdkPixmap *pixmap = NULL;
7694
7695 /* Creare una pixmap della dimensione appropriata */
7696 static gint
7697 configure_event (GtkWidget *widget, GdkEventConfigure *event)
7698 {
7699   if (pixmap)
7700     {
7701       gdk_pixmap_destroy(pixmap);
7702     }
7703   pixmap = gdk_pixmap_new(widget->window,
7704                           widget->allocation.width,
7705                           widget->allocation.height,
7706                           -1);
7707   gdk_draw_rectangle (pixmap,
7708                       widget->style->white_gc,
7709                       TRUE,
7710                       0, 0,
7711                       widget->allocation.width,
7712                       widget->allocation.height);
7713
7714   return TRUE;
7715 }
7716 </verb></tscreen>
7717
7718 La chiamata a <tt>gdk_draw_rectangle()</tt> inizialmente rende bianca l'intera
7719 pixmap. Fra un momento ne riparleremo.
7720
7721 <p>
7722 Il gestore dell'evento ``esposizione'', copia quindi la porzione appropriata
7723 della pixmap sullo schermo (determiniamo qual &egrave; l'area da ridisegnare usando
7724 il campo event->area dell'evento di esposizione):
7725
7726 <tscreen><verb>
7727 /* Ridisegna sullo schermo a partire dalla pixmap di supporto */
7728 static gint
7729 expose_event (GtkWidget *widget, GdkEventExpose *event)
7730 {
7731   gdk_draw_pixmap(widget->window,
7732                   widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
7733                   pixmap,
7734                   event->area.x, event->area.y,
7735                   event->area.x, event->area.y,
7736                   event->area.width, event->area.height);
7737
7738   return FALSE;
7739 }
7740 </verb></tscreen>
7741
7742 Abbiamo quindi visto come tenete aggiornato lo schermo con la nostra
7743 pixmap, ma come facciamo per disegnare delle cose interessanti sulla
7744 pixmap? Ci sono un bel po' di funzioni nella libreria GDK di GTK che
7745 servono per disegnare su superfici <em>disegnabili</em>. Una superficie
7746 disegnabile &egrave; semplicemente qualcosa su cui si pu&ograve; disegnare un'immagine.
7747 Pu&ograve; essere una finestra, una pixmap o una bitmap (un'immagine in bianco e
7748 nero). Abbiamo gi&agrave; visto sopra due di chiamate,
7749 <tt>gdk_draw_rectangle()</tt> and <tt>gdk_draw_pixmap()</tt>. La lista
7750 completa &egrave; la seguente:
7751
7752 <tscreen><verb>
7753 gdk_draw_line ()
7754 gdk_draw_rectangle ()
7755 gdk_draw_arc ()
7756 gdk_draw_polygon ()
7757 gdk_draw_string ()
7758 gdk_draw_text ()
7759 gdk_draw_pixmap ()
7760 gdk_draw_bitmap ()
7761 gdk_draw_image ()
7762 gdk_draw_points ()
7763 gdk_draw_segments ()
7764 </verb></tscreen>
7765
7766 Per ulteriori dettagli su queste funzioni, vedete la documentazione di
7767 riferimento nei file header <tt>&lt;gdk/gdk.h&gt;</tt>.
7768 Tutte queste funzioni hanno i medesimi primi due argomenti. Il primo
7769 &egrave; la superficie disegnabili su cui disegnare, il secondo &egrave; un 
7770 <em>contesto grafico</em> (GC). 
7771
7772 <p>
7773 Un contesto grafico incapsula delle informazioni riguardo a cose come
7774 il colore di sfondo e di primo piano e lo spessore della linea.
7775 GDK ha un ampio insieme di funzioni per crare e modificare contesti grafici,
7776 ma per tenere le cose semplici useremo solo dei contesti grafici predefiniti.
7777 Ogni widget ha uno stile associato (che pu&ograve; essere modificato agendo su un
7778 file gtkrc). Questo, fra le altre cose, contiene un certo numero di contesti
7779 grafici. Alcuni esempi di come accedere a questi contesti grafici sono
7780 i seguenti:
7781
7782 <tscreen><verb>
7783 widget->style->white_gc
7784 widget->style->black_gc
7785 widget->style->fg_gc[GTK_STATE_NORMAL]
7786 widget->style->bg_gc[GTK_WIDGET_STATE(widget)]
7787 </verb></tscreen>
7788
7789 I campi <tt>fg_gc</tt>, <tt>bg_gc</tt>, <tt>dark_gc</tt>, e
7790 <tt>light_gc</tt> sono indicizzati tramite un parametri di tipo
7791 <tt>GtkStateType</tt>, che pu&ograve; assumere i valori:
7792
7793 <tscreen><verb>
7794 GTK_STATE_NORMAL,
7795 GTK_STATE_ACTIVE,
7796 GTK_STATE_PRELIGHT,
7797 GTK_STATE_SELECTED,
7798 GTK_STATE_INSENSITIVE
7799 </verb></tscreen>
7800
7801 Per esempio, per  <tt/GTK_STATE_SELECTED/ il colore di sfondo predefinito
7802 &egrave; blu scuro e quello di primo piano bianco.
7803
7804 <p>
7805 La nostra funzione <tt>draw_brush()</tt>, che efettivamente disegna sullo
7806 schermo, diventa quindi:
7807
7808 <tscreen><verb>
7809 /* Disegna un rettangolo sullo schermo */
7810 static void
7811 draw_brush (GtkWidget *widget, gdouble x, gdouble y)
7812 {
7813   GdkRectangle update_rect;
7814
7815   update_rect.x = x - 5;
7816   update_rect.y = y - 5;
7817   update_rect.width = 10;
7818   update_rect.height = 10;
7819   gdk_draw_rectangle (pixmap,
7820                       widget->style->black_gc,
7821                       TRUE,
7822                       update_rect.x, update_rect.y,
7823                       update_rect.width, update_rect.height);
7824   gtk_widget_draw (widget, &amp;update_rect);
7825 }
7826 </verb></tscreen>
7827
7828 Dopo aver disegnato il rettangolo sulla pixmap, chiamiamo la funzione:
7829
7830 <tscreen><verb>
7831 void       gtk_widget_draw                (GtkWidget           *widget,
7832                                            GdkRectangle        *area);
7833 </verb></tscreen>
7834
7835 che notifica a X che l'area data dal parametro <tt>area</tt> deve essere
7836 aggiornata. X poi generer&agrave; un evento di esposizione (che pu&ograve; essere combinato
7837 con le aree passate da diverse chiamate a <tt>gtk_widget_draw()</tt>) che
7838 far&agrave; s&igrave; che il nostro gestore dell'evento di esposizione, copi le porzioni
7839 rilevanti sullo schermo.
7840
7841 <p>
7842 Abbiamo a questo punto creato tutto il programma di disegno, tranne che
7843 per qualche dettaglio irrilevante come la creazione della finestra principale.
7844 Il codice sorgente completo &egrave; reperibile dove avete ottenuto questo tutorial.
7845
7846 <sect1> Aggiungere il supporto per XInput
7847
7848 <p>
7849 Al giorno d'oggi &egrave; possibile acquistare dei dispositivi abbastanza a buon
7850 mercato, come tavolette grafice, che permettono di disegnare con una
7851 espressivit&agrave; artistica molto semplificata rispetto ad un mouse.
7852 Il modo pi&ugrave; semplice per usare questi dispositivi &egrave; di sostituirli
7853 semplicemente al mouse, ma in questo modo si perdono molti dei loro
7854 vantaggi, come:
7855
7856 <itemize>
7857 <item> Sensibilit&agrave; alla pressione
7858 <item> Sensibilit&agrave; all'inclinazione
7859 <item> Posizionamento infra-pixel
7860 <item> Ingressi multipli (per esempio, uno stilo che contiene sia una ``matita''
7861 sia una ``gomma'')
7862 </itemize>
7863
7864 Per ulteriori informazioni sulle estensioni XInput, vedere l'<url
7865 url="http://www.msc.cornell.edu/~otaylor/xinput/XInput-HOWTO.html"
7866 name="XInput-HOWTO">.
7867
7868 <p>
7869 Se esaminiamo, per esempio, la definizione completa della struttura
7870 GdkEventMotion, possiamo vedere che contiene dei campi per il supporto
7871 delle informazioni estese dai dispositivi.
7872
7873 <tscreen><verb>
7874 struct _GdkEventMotion
7875 {
7876   GdkEventType type;
7877   GdkWindow *window;
7878   guint32 time;
7879   gdouble x;
7880   gdouble y;
7881   gdouble pressure;
7882   gdouble xtilt;
7883   gdouble ytilt;
7884   guint state;
7885   gint16 is_hint;
7886   GdkInputSource source;
7887   guint32 deviceid;
7888 };
7889 </verb></tscreen>
7890
7891 <tt/pressure/ fornisce la pressione sotto forma di un numero decimale
7892 compreso fra 0 e 1. <tt/xtilt/ e <tt/ytilt/ possono assumere valori
7893 compresi fra -1 e 1, corrispondenti al grado di inclinazione in ciascuna
7894 direzione. <tt/source/ e <tt/deviceid/ specificano il dispositivo per il
7895 quale si &egrave; verificato l'evento in due modi distinti. <tt/source/  da alcune
7896 semplici informazioni sul tipo di dispositivo, e pu&ograve; assumere i valori:
7897
7898 <tscreen><verb>
7899 GDK_SOURCE_MOUSE
7900 GDK_SOURCE_PEN
7901 GDK_SOURCE_ERASER
7902 GDK_SOURCE_CURSOR
7903 </verb></tscreen>
7904
7905 <tt/deviceid/ specifica invece un identificativo numerico univoco per il
7906 dispositivo. Questo pu&ograve; essere a sua volta utilizzato per avere ulteriori
7907 informazioni sul dispositivo tramite la chiamata a <tt/gdk_input_list_devices()/
7908 (vedi sotto). Il valore speciale <tt/GDK_CORE_POINTER/ viene usato per identificare
7909 il dispositivo di puntamento principale (di solito il mouse).
7910
7911 <sect2> Abilitare le informazioni estese
7912
7913 <p>
7914 Per far s&igrave; che GTK sappia che ci interessano le informazioni estese dai
7915 dispositivi, basta aggiungere un'unica linea al nostro programma:
7916
7917 <tscreen><verb>
7918 gtk_widget_set_extension_events (drawing_area, GDK_EXTENSION_EVENTS_CURSOR);
7919 </verb></tscreen>
7920
7921 Dando il valore <tt/GDK_EXTENSION_EVENTS_CURSOR/, diciamo che ci interessano
7922 gli eventi relativi alle estensioni, ma solo se non dobbiamo disegnare da noi
7923 il nostro cursore. Si veda pi&ugrave; sotto alla sezione <ref
7924 id="sec_Further_Sophistications" name="Ulteriori Sofisticazioni"> per ulteriori
7925 informazioni sul modo si disegnare i cursori. Potremmo anche dare i valori
7926 <tt/GDK_EXTENSION_EVENTS_ALL/ se vogliamo disegnare il nostro cursore o
7927 <tt/GDK_EXTENSION_EVENTS_NONE/ se vogliamo tornare alle condizioni predefinite.
7928
7929 <p>
7930 Comunque, non finisce tutto qui. Non ci sono estensioni abilitate per difetto.
7931 Abbiamo bisogno di un meccanismo per permettere agli utenti l'abilitazione e
7932 la configurazione delle estensioni dei loro dispositivi, GTK fornisce il
7933 widget InputDialog per automatizzare questo processo. La seguente procedura
7934 mostra come gestire un widget InputDialog. Crea la finestra di dialogo nel
7935 caso non sia presente, mentre la porta in primo piano in caso contrario.
7936
7937 <tscreen><verb>
7938 void
7939 input_dialog_destroy (GtkWidget *w, gpointer data)
7940 {
7941   *((GtkWidget **)data) = NULL;
7942 }
7943
7944 void
7945 create_input_dialog ()
7946 {
7947   static GtkWidget *inputd = NULL;
7948
7949   if (!inputd)
7950     {
7951       inputd = gtk_input_dialog_new();
7952
7953       gtk_signal_connect (GTK_OBJECT(inputd), "destroy",
7954                           (GtkSignalFunc)input_dialog_destroy, &amp;inputd);
7955       gtk_signal_connect_object (GTK_OBJECT(GTK_INPUT_DIALOG(inputd)->close_button),
7956                                  "clicked",
7957                                  (GtkSignalFunc)gtk_widget_hide,
7958                                  GTK_OBJECT(inputd));
7959       gtk_widget_hide ( GTK_INPUT_DIALOG(inputd)->save_button);
7960
7961       gtk_widget_show (inputd);
7962     }
7963   else
7964     {
7965       if (!GTK_WIDGET_MAPPED(inputd))
7966         gtk_widget_show(inputd);
7967       else
7968         gdk_window_raise(inputd->window);
7969     }
7970 }
7971 </verb></tscreen>
7972
7973 (Notate come gestiamo questo dialogo. Con la connessione del segnale
7974 ``destroy'' ci assicuriamo di non tenerci in giro il puntatore al dialogo
7975 dopo che lo abbiamo distrutto, cosa che potrebbe portare ad un errore di
7976 segmentazione.)
7977
7978 <p>
7979 L'InputDialog ha due pulsanti, ``Close'' e ``Save'', i quali non hanno alcuna
7980 azione predefinita assegnata ad essi. Nella funzione precedente, abbiamo
7981 fatto in modo che ``Close'' nasconda la finestra di dialogo, e abbiamo nascosto
7982 il pulsante ``Save'' dal momento che in questo programma non implementiamo il
7983 salvataggio delle opzioni di XInput.
7984
7985 <sect2> Usare le informazioni estese
7986
7987 <p>
7988 Una volta abilitato il dipositivo, possiamo usare le informazioni estese
7989 che si trovano nei corrispondenti campi delle strutture che descrivono gli
7990 eventi. A dire il vero, l'utilizzo di questi campi &egrave; sempre sicuro, perch&eacute;
7991 sono tutti posti per difetto a valori ragionevoli ancje quando la gestione
7992 degli eventi estesi non &egrave; abilitata.
7993
7994 <p>
7995 Un cambiamento che dobbiamo fare &egrave; di chiamare <tt/gdk_input_window_get_pointer()/
7996 invece di <tt/gdk_window_get_pointer/. Ci&ograve; si rende necessario perch&eacute;
7997 <tt/gdk_window_get_pointer/ non restituisce le informazioni esetese.
7998
7999 <tscreen><verb>
8000 void gdk_input_window_get_pointer     (GdkWindow       *window,
8001                                        guint32         deviceid,
8002                                        gdouble         *x,
8003                                        gdouble         *y,
8004                                        gdouble         *pressure,
8005                                        gdouble         *xtilt,
8006                                        gdouble         *ytilt,
8007                                        GdkModifierType *mask);
8008 </verb></tscreen>
8009
8010 Quando chiamiamo questa funzione, dobbiamo specificare l'identificativo
8011 del dispositivo e la finestra. Normalmente questo identificativo lo si
8012 ottiene dal campo <tt/deviceid/ della struttura dell'evento.
8013 Questa funzione restituir&agrave; valori ragionevoli nel caso che la gestione
8014 degli eventi estesi non sia attivata (in questo caso, <tt/event->deviceid/
8015 avr&agrave; il valore <tt/GDK_CORE_POINTER/).
8016
8017 Quindi, la struttura di base dei gestori degli eventi relativi alla
8018 pressione di bottoni e ai movomenti non cambia molto - abbiamo solo
8019 bisogno di aggiungere il codice necessario per tenere conto delle
8020 informazioni estese.
8021
8022 <tscreen><verb>
8023 static gint
8024 button_press_event (GtkWidget *widget, GdkEventButton *event)
8025 {
8026   print_button_press (event->deviceid);
8027   
8028   if (event->button == 1 &amp;&amp; pixmap != NULL)
8029     draw_brush (widget, event->source, event->x, event->y, event->pressure);
8030
8031   return TRUE;
8032 }
8033
8034 static gint
8035 motion_notify_event (GtkWidget *widget, GdkEventMotion *event)
8036 {
8037   gdouble x, y;
8038   gdouble pressure;
8039   GdkModifierType state;
8040
8041   if (event->is_hint)
8042     gdk_input_window_get_pointer (event->window, event->deviceid,
8043                                   &amp;x, &amp;y, &amp;pressure, NULL, NULL, &amp;state);
8044   else
8045     {
8046       x = event->x;
8047       y = event->y;
8048       pressure = event->pressure;
8049       state = event->state;
8050     }
8051     
8052   if (state &amp; GDK_BUTTON1_MASK &amp;&amp; pixmap != NULL)
8053     draw_brush (widget, event->source, x, y, pressure);
8054   
8055   return TRUE;
8056 }
8057 </verb></tscreen>
8058
8059 Avremo anche bisogno di fare qualcosa con queste nuove informazioni. La
8060 nostra nuova funzione <tt/draw_brush/ disegna con un colore diverso per
8061 ogni <tt/event->source/ e cambia la dimensione della linea in funzione
8062 della pressione.
8063
8064 <tscreen><verb>
8065 /* Disegna un rettangolo sullo schermo, con la dimensione dipendente
8066    dalla pressione e il colore dipendente dal tipo di dispositivo */
8067 static void
8068 draw_brush (GtkWidget *widget, GdkInputSource source,
8069             gdouble x, gdouble y, gdouble pressure)
8070 {
8071   GdkGC *gc;
8072   GdkRectangle update_rect;
8073
8074   switch (source)
8075     {
8076     case GDK_SOURCE_MOUSE:
8077       gc = widget->style->dark_gc[GTK_WIDGET_STATE (widget)];
8078       break;
8079     case GDK_SOURCE_PEN:
8080       gc = widget->style->black_gc;
8081       break;
8082     case GDK_SOURCE_ERASER:
8083       gc = widget->style->white_gc;
8084       break;
8085     default:
8086       gc = widget->style->light_gc[GTK_WIDGET_STATE (widget)];
8087     }
8088
8089   update_rect.x = x - 10 * pressure;
8090   update_rect.y = y - 10 * pressure;
8091   update_rect.width = 20 * pressure;
8092   update_rect.height = 20 * pressure;
8093   gdk_draw_rectangle (pixmap, gc, TRUE,
8094                       update_rect.x, update_rect.y,
8095                       update_rect.width, update_rect.height);
8096   gtk_widget_draw (widget, &amp;update_rect);
8097 }
8098 </verb></tscreen>
8099
8100 <sect2> Trovare ulteriori informazioni su di un dispositivo
8101
8102 <p>
8103 Come esempio del modo di trovare altre informazioni su di un dispositivo,
8104 il nostro programma stamper&agrave; il nome di ogni dispositivo che genera un
8105 evento di pressione di un pulsante. Per avere il nome di un dispositivo,
8106 chiamiamo la funzione
8107
8108 <tscreen><verb>
8109 GList *gdk_input_list_devices               (void);
8110 </verb></tscreen>
8111
8112 che restituisce una GList (un tipo di lista collegata che si trova nella
8113 libreria glib) di strutture di tipo GdkDeviceInfo. La definizione di
8114 GdkDeviceInfo &egrave; la seguente:
8115
8116 <tscreen><verb>
8117 struct _GdkDeviceInfo
8118 {
8119   guint32 deviceid;
8120   gchar *name;
8121   GdkInputSource source;
8122   GdkInputMode mode;
8123   gint has_cursor;
8124   gint num_axes;
8125   GdkAxisUse *axes;
8126   gint num_keys;
8127   GdkDeviceKey *keys;
8128 };
8129 </verb></tscreen>
8130
8131 La maggior parte di questi campi rappresentano informazioni di configurazione
8132 che potete ignorare a meno che non implementiate il salvataggio della
8133 configurazione di un XInput. Quelle che ci interessano sono <tt/name/, che
8134 &egrave; semplicemente il nome che X assegna al dispositivo, e <tt/has_cursor/. Anche
8135 <tt/has_cursor/ non &egrave; informazione di configurazione, e indica, nel caso
8136 abbia valore ``falso'', che dobbiamo disegnare da soli il nostro cursore. Ma
8137 dal momento che abbiamo specificato <tt/GDK_EXTENSION_EVENTS_CURSOR/,
8138 possiamo anche non preoccuparcene.
8139
8140 <p>
8141
8142 La nostra funzione <tt/print_button_press()/ scorre semplicemente la lista
8143 che &egrave; stata restituita finch&eacute; non trova il valore corretto, e poi stampa
8144 il nome del dispositivo.
8145
8146 <tscreen><verb>
8147 static void
8148 print_button_press (guint32 deviceid)
8149 {
8150   GList *tmp_list;
8151
8152   /* gdk_input_list_devices restituisce una lista interna, cos&igrave; poi
8153      non dobbiamo liberarla */
8154   tmp_list = gdk_input_list_devices();
8155
8156   while (tmp_list)
8157     {
8158       GdkDeviceInfo *info = (GdkDeviceInfo *)tmp_list->data;
8159
8160       if (info->deviceid == deviceid)
8161         {
8162           printf("Button press on device '%s'\n", info->name);
8163           return;
8164         }
8165
8166       tmp_list = tmp_list->next;
8167     }
8168 }
8169 </verb></tscreen>
8170 Questo completa i cambiamenti necessari per usare gli XInput nel nostro
8171 programma. Come per la prima versione, i sorgenti completi sono prelevabili
8172 da dove avete prelevato questo tutorial.
8173
8174 <sect2> Ulteriori sofisticazioni <label id="sec_Further_Sophistications">
8175
8176 <p>
8177 Anche se ora il nostro programma supporta XInput pittosto bene, gli mancano
8178 alcune caratteristiche che probabilmente vorremmo mettere in una applicazione
8179 completa. In primo luogo, probabilmente all'utente non far&agrave; piacere dover
8180 configurare i propri dispositivi ogni volta che lanciano il programma, per
8181 cui dovremmo dare la possibilit&agrave; di salvare la configurazione dei dispositivi.
8182 Ci&ograve; pu&ograve; essere fatto scorrendo la lista restituita da <tt/gdk_input_list_devices()/
8183 e scrivendo la configurazione su di un file.
8184
8185 <p>
8186 Per tornare allo stato salvato la prossima volta che il programma viene
8187 eseguito, GDK mette a disposizione delle funzioni per cambiare la configurazione
8188 dei dispositivi:
8189
8190 <tscreen><verb>
8191 gdk_input_set_extension_events()
8192 gdk_input_set_source()
8193 gdk_input_set_mode()
8194 gdk_input_set_axes()
8195 gdk_input_set_key()
8196 </verb></tscreen>
8197
8198 (La lista restituita da <tt/gdk_input_list_devices()/ non dovrebbe
8199 essere modificata direttamente.) Un esempio di come fare pu&ograve; essere
8200 trovato nel programma di disegno gsumi (disponibile da <htmlurl
8201 url="http://www.msc.cornell.edu/~otaylor/gsumi/"
8202 name="http://www.msc.cornell.edu/~otaylor/gsumi/">). Sarebbe bello
8203 avere alla fine un modo standard di recuperare le informazioni per tutte
8204 le applicazioni. Questo probabilmente appartiene ad un livello un po'
8205 pi&ugrave; elevato ripetto a GTK, forse alla libreria GNOME.
8206
8207 <p>
8208 Un'altra notevole omissione a cui abbiamo accennato precedentemente &egrave; il
8209 fatto di non disegnare il cursore direttamente. Piattaforme diverse da
8210 XFree86 non permettono in questo momento di usare contemporaneamente un
8211 dispositivo sia come puntatore principale sia direttamente da una
8212 applicazione. Vedere  <url url="http://www.msc.cornell.edu/~otaylor/xinput/XInput-HOWTO.html"
8213 name="XInput-HOWTO"> per ulteriori informazioni. Ci&ograve; significa che le
8214 applicazioni che vogliono rivolgersi al pubblico pi&ugrave; ampio dovranno prevedere
8215 di disegnare esse stesse il proprio cursore.
8216
8217 <p>
8218 Un'applicazione che voglia disegnare il proprio cursore dovr&agrave; fare due cose:
8219 determinare se il dispositivo corrente necessita che venga disegnato un
8220 cursore, e determinare se il dispositivo corrente &egrave; in prossimit&agrave;. (Se il
8221 dispositivo &egrave; una tavoletta grafica, un tocco di finezza &egrave; fare sparire
8222 il puntatore quando lo stilo viene sollevato dalla tavoletta. Quando c'&egrave;
8223 contatto fra lo stilo e la tavoletta, si dice che il dispositivo &egrave; ``in
8224 prossimit&agrave;".) La prima cosa viene fatta scorrendo la lista dei dispositivi,
8225 come abbiamo fatto per trovare il nome del dispositivo. La seconda cosa
8226 viene ottenuta selezionando gli eventi ``proximity_out''. Un esempio di
8227 disegno del proprio cursore si trova nel programma 'testinput' incluso nella
8228 distribuzione di GTK.
8229
8230 <sect>Consigli per scrivere Applicazioni GTK
8231
8232 <p>
8233
8234 Questa sezione &egrave; semplicemente una raccolta di saggezza, una
8235 guida di stile e un aiuto per creare buone applicazioni GTK. E' totalmente
8236 inutile per ora perch&eacute; &egrave; solamente un appunto.
8237
8238 Usa autoconf e automake! Sono tuoi amici :) Ho intenzione di fare una
8239 piccola introduzione su di loro qui.
8240
8241 <sect>Contributi
8242 <p>
8243
8244 Questo documento, come molti altri grandi software fuori di qui, &egrave; stato 
8245 creato da volontari. Se sai tutto quello che c'&egrave; da sapere su GTK e non
8246 lo hai trovato qui allora considera la possibilit&agrave; di contribuire a questo
8247 documento.
8248
8249 <p>
8250 Se decidi di contribuire, per favore trasmettimi il tuo testo a 
8251 <tt><htmlurl url="mailto:slow@intergate.bc.ca"
8252 name="slow@intergate.bc.ca"></tt>. Inoltre, Si consapevole che l'intero 
8253 documento &egrave; ``free'', e ogni tua aggiunta sar&agrave; considerata allo stesso modo.
8254 Per questo motivo le persone possono usare porzioni dei tuoi esempi nei loro
8255 programmi, copie di questo documento possono essere distribuite all'infinito,
8256 ecc...
8257
8258 <p>
8259
8260 Grazie.
8261
8262
8263 <sect>Credits
8264 <p>
8265 Voglio qui ringraziare le persone che seguono, per il loro contributo
8266 alla stesura di questo testo.
8267
8268 <itemize>
8269 <item>Bawer Dagdeviren, <tt><htmlurl url="mailto:chamele0n@geocities.com"
8270 name="chamele0n@geocities.com"></tt> per il tutorial sui men&ugrave;.
8271
8272 <item>Raph Levien, <tt><htmlurl url="mailto:raph@acm.org"
8273                          name="raph@acm.org"></tt>
8274 per il "hello world" alla GTK, l'immpacchettamento del widget, e in generale
8275 per tutta la sua saggezza.
8276 Lui ha anche donato una casa per questo tutorial.
8277
8278 <item>Peter Mattis, <tt><htmlurl url="mailto:petm@xcf.berkeley.edu"
8279 name="petm@xcf.berkeley.edu"></tt> Per il pi&ugrave; semplice programma GTK e l'abilit&agrave;
8280 di farlo. :)
8281
8282 <item>Werner Koch <tt><htmlurl url="mailto:werner.koch@guug.de"
8283 name="werner.koch@guug.de"></tt> per la conversione da testo semplice a SGML
8284 e la gerarchia delle classi di widget.
8285
8286 <item>Mark Crichton <tt><htmlurl url="mailto:crichton@expert.cc.purdue.edu"
8287 name="crichton@expert.cc.purdue.edu"></tt> per il codice della "MenuFactory"
8288 e per la parte sull'impacchettamento nelle tabelle del tutorial.
8289
8290 <item>Owen Taylor <tt><htmlurl url="mailto:owt1@cornell.edu"
8291 name="mailto:owt1@cornell.edu"></tt> per la sezione del  widget EventBox
8292 (e il patch alla distribuzione). Lui &egrave; anche responsabile per il codice
8293 e il tutorial delle selezioni, come per la sezione sulla scrittura di un 
8294 proprio widget, e l'applicazione d'esempio. Grazie di tutto Owen.
8295
8296 <item>Mark VanderBoom <tt><htmlurl url="mailto:mvboom42@calvin.edu"
8297 name="mailto:mailto:mvboom42@calvin.edu"></tt> per il suo meraviglioso lavoro
8298 sul Notebook, Progres Bar, Dialogs e File selection. Grazie molto Mark. Sei
8299 stato di grande aiuto.
8300
8301 <item>Tim Janik <tt><htmlurl url="mailto:timj@psynet.net"
8302 name="mailto:timj@psynet.net"></tt> per il suo grande lavoro sul widget List.
8303 Grazie Tim :)
8304
8305 <item> Michael K. Johnson <tt><htmlurl url="mailto:johnsonm@redhat.com"
8306 name="johnsonm@redhat.com"> </tt> per le informazioni e il codice dei menu
8307 a comparsa.
8308
8309 </itemize>
8310 <p>
8311 E a tutti voi che avete fatto commenti e avete aiutato a raffinare questo documento.
8312 <p>
8313
8314 Thanks.
8315
8316 <sect> Copying
8317 <p>
8318 This tutorial is Copyright (c) 1997 Ian Main 
8319
8320 La traduzione italiana &egrave; sotto Copyright (c) 1997-1998 di Michel Morelli,
8321 Daniele Canazza e Antonio Schifano.
8322
8323 <p>
8324
8325 This program is free software; you can redistribute it and/or
8326 modify it under the terms of the GNU General Public License
8327 as published by the Free Software Foundation; either version 2
8328 of the License, or (at your option) any later version.
8329 <p>
8330 This program is distributed in the hope that it will be useful,
8331 but WITHOUT ANY WARRANTY; without even the implied warranty of
8332 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
8333 GNU General Public License for more details.
8334 <p>
8335 You should have received a copy of the GNU General Public License
8336 along with this program; if not, write to the Free Software
8337 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
8338
8339 </article>
8340