Le selezioni sono un tipo di comunicazione tra processi supportato da GTK. Una selezione identifica un frammento di dati; per esempio, una porzione di testo selezionata dall'utente in qualche modo, magari con il mouse. Su un display solo un'applicazione alla volta (il proprietario) puó essere proprietaria di una particolare selezione, sicché quando un'applicazione richiede una selezione il precedente proprietario deve comunicare all'utente che la selezione è stata ceduta. Altre applicazioni possono richiedere il contenuto di una selezione in diverse forme, chiamate obiettivi. Ci può essere un numero qualsiasi di selezioni, ma la maggior parte delle applicazioni X può gestirne solo una, la selezione primaria.
Nella maggior parte dei casi per una applicazione GTK non è necessario gestire esplicitamente le selezioni. I widget standard, come quello di Ingresso, hanno già la capacità di chiedere la selezione se necessario (p. e., quando l'utente seleziona sul testo), e di recuperare il contenuto di una selezione di un altro widget o di un'altra applicazione (p. e., quando l'utente clicca il tasto centrale del mouse). Ci possono comunque essere dei casi nei quali si vuole dare ad altri widget la capacità di fornire la selezione, o si vogliono recuperare degli obiettivi non supportati direttamente.
Un concetto fondamentale necessario per comprendere la gestione delle
selezioni è quello di atomo. Un atomo è un intero
che identifica univocamente una stringa (su un certo display).
Certi atomi sono predefiniti dal server X, e in alcuni casi in gtk.h
ci sono costanti corrispondenti a questi atomi. Per esempio, la costante
GDK_PRIMARY_SELECTION corrisponde alla stringa ``PRIMARY''.
Negli altri casi bisogna usare le funzioni gdk_atom_intern()
per ottenere l'atomo corrispondente ad una stringa, e gdk_atom_name()
per ottenere il nome di un atomo. Sia le selezioni sia gli obiettivi sono
identificati da atomi.
Il recupero di una selezione è un processo asincrono. Per iniziare il processo, si chiama:
gint gtk_selection_convert (GtkWidget *widget,
GdkAtom selection,
GdkAtom target,
guint32 time)
Questo converte la selezione nella forma specificata
dall'obiettivo target. Se possibile, il campo time
dovrebbe essere il tempo dell'evento che ha attivato la selezione.
Questo aiuta a far si che gli eventi avvengano nell'ordine in cui
l'utente li ha richiesti. Se comunque non fosse disponibile (per
esempio, se la conversione è stata attivata da un segnale di
``cliccato''), allora si può usare la costante
GDK_CURRENT_TIME.
Quando il proprietario di una selezione risponde ad una richiesta,
un segnale ``selection_received'' (selezione ricevuta) viene inviato
alla vostra applicazione. Il gestore di questo segnale riceve un
puntatore ad una struttura GtkSelectionData, che è
definita nel modo seguente:
struct _GtkSelectionData
{
GdkAtom selection;
GdkAtom target;
GdkAtom type;
gint format;
guchar *data;
gint length;
};
selection e target sono i valori da voi specificati
nella chiamata gtk_selection_convert(). type è
un atomo che identifica il tipo di dati restituiti dal proprietario della
selezione. Alcuni valori possibili sono ``STRING'', una stringa di
caratteri latin-1, ``ATOM'', una serie di atomi, ``INTEGER'', un intero, ecc.
La maggior parte degli obiettivi può restituire solo un tipo.
format ci dà la lunghezza delle unità (per esempio caratteri)
in bit. Di solito, quando si ricevono i dati non ci si cura di questo.
data è un puntatore ai dati restituiti, e length
è la lunghezza dei dati restituiti, in byte. Se length
è negativo allora si è verificato un errore e non è
stato possibile recuperare la selezione. Questo può avvenire se
nessuna applicazione era proprietaria della selezione, o se si è
richiesto un obiettivo non supportato dall'applicazione. Viene garantito
che il buffer sia un byte più lungo di length; il byte
in più sarà sempre zero, in modo che non sia necessario
ricopiare le stringhe solo per farle terminare con zero.
Nell'esempio che segue viene recuperato l'obiettivo speciale ``TARGETS'', che è una lista di tutti gli obiettivi in cui può essere convertita la selezione.
/* gettargets.c */
#include <gtk/gtk.h>
void selection_received (GtkWidget *widget,
GtkSelectionData *selection_data,
gpointer data);
/* Gestore di segnale chiamato quando l'utente clicca nel bottone */
/* "Get Targets" */
void
get_targets (GtkWidget *widget, gpointer data)
{
static GdkAtom targets_atom = GDK_NONE;
/* Prende l'atomo corrispondente alla stringa "TARGETS" */
if (targets_atom == GDK_NONE)
targets_atom = gdk_atom_intern ("TARGETS", FALSE);
/* E richiede l'obiettivo "TARGETS" per la selezione primaria */
gtk_selection_convert (widget, GDK_SELECTION_PRIMARY, targets_atom,
GDK_CURRENT_TIME);
}
/* Gestore di segnale chiamato quando il proprietario della selezione */
/* restituisce i dati */
void
selection_received (GtkWidget *widget, GtkSelectionData *selection_data,
gpointer data)
{
GdkAtom *atoms;
GList *item_list;
int i;
/* **** IMPORTANTE **** Controlla che il recupero sia riuscito */
if (selection_data->length < 0)
{
g_print ("Selection retrieval failed\n");
return;
}
/* Make sure we got the data in the expected form */
if (selection_data->type != GDK_SELECTION_TYPE_ATOM)
{
g_print ("Selection \"TARGETS\" was not returned as atoms!\n");
return;
}
/* Stampa gli atomi ricevuti */
atoms = (GdkAtom *)selection_data->data;
item_list = NULL;
for (i=0; i<selection_data->length/sizeof(GdkAtom); i++)
{
char *name;
name = gdk_atom_name (atoms[i]);
if (name != NULL)
g_print ("%s\n",name);
else
g_print ("(bad atom)\n");
}
return;
}
int
main (int argc, char *argv[])
{
GtkWidget *window;
GtkWidget *button;
gtk_init (&argc, &argv);
/* Create the toplevel window */
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (window), "Event Box");
gtk_container_border_width (GTK_CONTAINER (window), 10);
gtk_signal_connect (GTK_OBJECT (window), "destroy",
GTK_SIGNAL_FUNC (gtk_exit), NULL);
/* Crea un bottone che l'utente può cliccare per ottenere gli obiettivi */
button = gtk_button_new_with_label ("Get Targets");
gtk_container_add (GTK_CONTAINER (window), button);
gtk_signal_connect (GTK_OBJECT(button), "clicked",
GTK_SIGNAL_FUNC (get_targets), NULL);
gtk_signal_connect (GTK_OBJECT(button), "selection_received",
GTK_SIGNAL_FUNC (selection_received), NULL);
gtk_widget_show (button);
gtk_widget_show (window);
gtk_main ();
return 0;
}
Fornire la selezione è un po' più complicato. Bisogna registrare i gestori che verranno chiamati quando viene richiesta la propria selezione. Per ogni coppia selezione/obiettivo che si gestirà occorre una chiamata a:
void gtk_selection_add_handler (GtkWidget *widget,
GdkAtom selection,
GdkAtom target,
GtkSelectionFunction function,
GtkRemoveFunction plic gchar *signal_name);
void gtk_widget_activate (GtkWidget *widget);
void gtk_widget_set_name (GtkWidget *widget,
gchar *name);
gchar* gtk_widget_get_name (GtkWidget *widget);
void gtk_widget_set_sensitive (GtkWidget *widget,
gint sensitive);
void gtk_widget_set_style (GtkWidget *widget,
GtkStyle *style);
GtkStyle* gtk_widget_get_style (GtkWidget *widget);
GtkStyle* gtk_widget_get_default_style (void);
void gtk_widget_set_uposition (GtkWidget *widget,
gint x,
gint y);
void gtk_widget_set_usize (GtkWidget *widget,
gint width,
gint height);
void gtk_widget_grab_focus (GtkWidget *widget);
void gtk_widget_show (GtkWidget *widget);
void gtk_widget_hide (GtkWidget *widget);