Avanti Indietro Indice

16. La gestione delle selezioni

16.1 Overview

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.

16.2 Recuperare le selezioni

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;
}

16.3 Fornire una selezione

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);


Avanti Indietro Indice ./usr/share/doc/libgtk1.2-doc/gtk-tutorial-it-html/gtk_tut_it-15.html0000644000000000000000000001074610066303654025374 0ustar rootroot00000000000000 GTK Tutorial: Funzioni periodiche, di I/O e di attesa Avanti Indietro Indice

15. Funzioni periodiche, di I/O e di attesa

15.1 Funzioni periodiche

Probabilmente vi sarete chiesti come far fare qualcosa di utile a GTK durante la chiamata alla gtk_main(). Ci sono diverse possibilità. Usando le seguenti funzioni si possono creare funzioni che vengono chiamate periodicamente.

gint gtk_timeout_add (guint32 interval,
                      GtkFunction function,
                      gpointer data);

Il primo argomento è il numero di millisecondi tra le chiamate alla funzione. Il secondo è la funzione periodica, mentre il terzo rappresenta i dati che vengono passati alla funzione. Il valore restituito è un'etichetta che può essere utilizzata per fermare la chiamata periodica, passandolo alla funzione:

void gtk_timeout_remove (gint tag);

La chiamata periodica si ferma anche se la funzione periodica ritorna zero o FALSE. Naturalmente questo vuol dire che se si vuole che la funzione periodica continui ad essere richiamata, essa deve restituire un valore non nullo, cioè TRUE.

La dichiarazione della funzione periodica dovrebbe essere come questa:

gint timeout_callback (gpointer data);

15.2 Controllo dell'I/O

Un'altra utile caratteristica di GTK è la possibilità di fargli controllare che siano verificate certe condizioni su un descrittore di file (come quelli restituiti da open(2) o socket(2)). Questo è utile in particolar modo per le applicazioni di rete. La funzione è la seguente:

gint gdk_input_add (gint source,
                    GdkInputCondition condition,
                    GdkInputFunction  function,
                    gpointer data);

Il primo argomento è il descrittore che si desidera venga controllato, mentre il secondo specifica quale condizione si vuole che GDK controlli. Questa può essere una tra:

GDK_INPUT_READ - Chiama la funzione quando ci sono dati pronti per la lettura nel descrittore di file.

GDK_INPUT_WRITE - Chiama la funzione quando il descrittore di file è pronto per la scrittura.

Come sicuramente avrete già intuito, il terzo parametro è la funzione da chiamare quando la condizione specificata è soddisfatta, mentre il quarto rappresenta i dati da passare a questa funzione.

Il valore di ritorno è un etichetta che può essere usata per fermare il controllo di GDK sul descrittore di file, usando la seguente funzione:

void gdk_input_remove (gint tag);

La funzione da richiamare va dichiarata così:

void input_callback (gpointer data, gint source, 
                     GdkInputCondition condition);

15.3 Funzioni di attesa (``Idle'')

Cosa fare se si ha una funzione che si vuole venga chiamata quando non sta accadendo nient'altro?

gint gtk_idle_add (GtkFunction function,
                   gpointer data);

Questa fa si che GDK chiami la funzione specificata quando non c'è nessuna altra operazione in corso.