Il ruolo primario del ciclo principale di GTK+ è quello di monitorare gli eventi su un descrittore connesso al server X, e inviarli ai widget.
la sezione Ricevere gli eventi di GDK in GTK+ nel il capitolo I fondamenti di GDK
descrive la gestione degli eventi all'interno del ciclo principale con maggiori dettagli. Questa sezione mostra il ciclo in termini generali, e descrive come aggiungere funzionalità a questo: possono essere chiamate funzioni callback quando il ciclo è in pausa, a specifici intervalli oppure quando il ciclo stesso esce.
Il ciclo principale è fondamentalmente implementato in glib, che fornisce una astrazione generale un ciclo di questo genere. GTK+ collega il ciclo principale fornite da gli alla connessione di GDK al server X, e fornisce una facile interfaccia (il ciclo di glip è leggermente più a basso livello di quello fornito da GTK+). L'interfaccia del ciclo di GTK+ è descritta in
Figura 28
.
gtk_main() avvia il ciclo. gtk_main() non ritornerà fino a che non verrà chiamata la funzione gtk_main_quit(). gtk_main() può essere chiamata ricorsivamente. Ciascuna chiamata a gtk_main_quit() permette la terminazione di un'unica istanza di gtk_main(). gtk_main_level() restituisce il livello di ricorsione, cioè 0 se non esiste nessuna gtk_main() all'interno dello stack, 1 se una sola gtk_main() è in esecuzione, e così via.
Tutte le istanze di gtk_main() sono funzionalmente identiche. Tutte controllano la medesima connessione al server X sulla stessa coda di eventi. Le istanze di gtk_main() vengono utilizzate per bloccare, interrompere il controllo di flusso finché non vengono soddisfatte delle condizioni. Tutti gli applicativi GTK+ utilizzano questa tecnica per evitare che la funzione main() termini durante l'esecuzione dell'applicazione. La funzione gnome_dialog_run() (maggiori informazioni nel
la sezione Finestre di dialogo modali nel il capitolo Comunicare con l'utente: finestre di dialogo
) utilizza un ciclo principale ricorsivo, che non termina fino a che l'utente non preme un pulsante della finestra di dialogo.
Talvolta desiderate elaborare alcuni eventi particolari, senza però lasciare la gestione del flusso a gtk_main(). Potete eseguire una singola iterazione del ciclo principale chiamando gtk_main_iteration(). Questo può processare un singolo evento, ad esempio, dipende su quale task sono in attesa. Potete controllare se un qualunque evento è in attesa di essere processato utilizzando la funzione gtk_events_pending(). Assieme, queste due funzioni permettono di ottenere il controllo del flusso. Ad esempio, durante una lunga serie di calcoli, desiderate mostrare una barra di progressione. Dovete permettere al ciclo principale di GTK+ di essere eseguito, in modo tale che la barra di progressione possa essere ridisegnata. Utilizzate questo codice:
|
while (gtk_events_pending())
gtk_main_iteration();
|
Una funzione di uscita è una callback da chiamare quando è chiamata gtk_main_quit(). In altre parole, la callback viene eseguita esattamente prima del ritorno di gtk_main(). La callback deve essere una GtkFunction, definita in questo modo:
|
typedef gint (*GtkFunction) (gpointer data);
|
Le funzioni di uscita vengono aggiunte utilizzando gtk_quit_add() (
Figura 29
). Quando una di queste viene aggiunta, dovete specificare il livello di ciclo, restituito da gtk_main_level(). Il secondo e terzo argomento specificano una callback e i dati per questa.
Il valore restituito dalla callback indica se questa deve essere chiamata
nuovamente. Finché la callback restituisce TRUE, questa chiamata verrà ripetuta. Non appena verrà restituito il valore FALSE, verrà terminata. Quando tutte le funzioni di uscita avranno restituito il valore FALSE, gtk_main() potrà uscire.
gtk_quit_add() restituisce un numero identificatore che può essere utilizzato per rimuovere una funzione di uscita attraverso gtk_quit_remove(). È possibile inoltre rimuovere una funzione di uscita passando alla callback come argomento dati la chiamata a gtk_quit_remove_by_data().
Le funzioni di Timeout vengono associate e
dissociate esattamente come le funzioni di uscita. La callback associatavi è
inoltre identica. gtk_timeout_add() aspetta come
argomento un intervallo. La callback viene
chiamata ogni intervallo di millisecondi. Se la callback restituisce FALSE, questa viene rimossa dalla lista delle funzioni di timeout, come se aveste chiamato gtk_timeout_remove() in una funzione di timeout. Questa modifica la lista dei timeout mentre GTK+ esegue iterazioni sopra di essa, causando un errore fatale. Dovete invece far restituire il valore FALSE per rimuovere la funzione.
Le funzioni di pausa vengono eseguite continuamente mentre il ciclo princpale di GTK+ non ne esegue nessuna. Le funzioni di pausa vengono eseguite unicamente quando la coda degli eventi è vuota e il ciclo principale è momentaneamente disoccupato, in attesa che accada qualcosa. Quando queste restituiscono un valore uguale TRUE vengono eseguite, mentre restituendo FALSE vengono rimosse. Stesso effetto del chiamare gtk_idle_remove().
La API delle funzioni di pausa, mostrata in
Figura 31
, è pressochè identica a quelle delle funzioni di uscita e di timeout. Nuovamente, gtk_idel_remove() non deve essere chiamata all'interno della funzione. Restituite un valore uguale a FALSE per rimuovere la funzione.
Le funzioni di input vengono gestite a livello di GDK. Queste vengono invocate quando un determinato descrittore di file è pronto per la lettura o scrittura. Sono particolarmente utili per le applicazioni di rete.
Per aggiungere una funzione di input è necessario specificare il descrittore del file da monitorare, lo stato che attendete (pronto per leggere o scrivere) e una coppia callback/dati.
Figura 32
mostra la API. Le funzioni possono essere rimosse utilizzando il tag restituito dalla funzione gdk_input_add(). Diversamente dalle funzioni di pausa, uscita o timeout, è sicuro chiamare gdk_input_remove() all'interno della funzione di input.
Per specificare la condizione da attendere, utilizzare i flag del GdkInputCondition: GDK_INPUT_READ, GDK_INPUT_WRITE, e GDK_INPUT_EXCEPTION. Questi corrispondono ai tre descrittori di file passati alla chiamata di sistema select(). Consultate un buon manuale di programmazione UNIX per maggiori dettagli. Se una qualunque condizione è soddisfatta, la funzione di input viene chiamata.
La callback dovrebbe appartenere a questa tipologia:
|
typedef void (*GdkInputFunction) (gpointer data,
gint source_fd,
GdkInputCondition condition);
|
Questa riceve i vosti dati per la callback, il descrittore del file monitorato e le condizioni soddisfatte.