GTK+ 2.0 Tutorial
<<< Previous | Managing Selections | Next >>>

# Retrieving the selection

Retrieving the selection is an asynchronous process. To start the process, you call:

    gboolean gtk_selection_convert( GtkWidget *widget,
                                    GdkAtom    selection,
                                    GdkAtom    target,
                                    guint32    time );

This converts the selection into the form specified by `target`. If at all possible, the time field should be the time from the event that triggered the selection. This helps make sure that events occur in the order that the user requested them. However, if it is not available (for instance, if the conversion was triggered by a "clicked" signal), then you can use the constant `GDK_CURRENT_TIME`.

When the selection owner responds to the request, a "selection_received" signal is sent to your application. The handler for this signal receives a pointer to a `GtkSelectionData` structure, which is defined as:

    struct _GtkSelectionData
    {
      GdkAtom selection;
      GdkAtom target;
      GdkAtom type;
      gint    format;
      guchar *data;
      gint    length;
    };

`selection` and `target` are the values you gave in your `gtk_selection_convert()` call. `type` is an atom that identifies the type of data returned by the selection owner. Some possible values are "STRING", a string of latin-1 characters, "ATOM", a series of atoms, "INTEGER", an integer, etc. Most targets can only return one type. `format` gives the length of the units (for instance characters) in bits. Usually, you don't care about this when receiving data. `data` is a pointer to the returned data, and `length` gives the length of the returned data, in bytes. If `length` is negative, then an error occurred and the selection could not be retrieved. This might happen if no application owned the selection, or if you requested a target that the application didn't support. The buffer is actually guaranteed to be one byte longer than `length`; the extra byte will always be zero, so it isn't necessary to make a copy of strings just to nul-terminate them.

In the following example, we retrieve the special target "TARGETS", which is a list of all targets into which the selection can be converted.

    #include <stdlib.h>
    #include <gtk/gtk.h>

    static void selection_received( GtkWidget        *widget,
                                    GtkSelectionData *selection_data,
                                    gpointer          data );

    /* Signal handler invoked when user clicks on the "Get Targets" button */
    static void get_targets( GtkWidget *widget,
                             gpointer data )
    {
      static GdkAtom targets_atom = GDK_NONE;
      GtkWidget *window = (GtkWidget *)data;

      /* Get the atom corresponding to the string "TARGETS" */
      if (targets_atom == GDK_NONE)
        targets_atom = gdk_atom_intern ("TARGETS", FALSE);

      /* And request the "TARGETS" target for the primary selection */
      gtk_selection_convert (window, GDK_SELECTION_PRIMARY, targets_atom,
    			 GDK_CURRENT_TIME);
    }

    /* Signal handler called when the selections owner returns the data */
    static void selection_received( GtkWidget        *widget,
                                    GtkSelectionData *selection_data,
                                    gpointer          data )
    {
      GdkAtom *atoms;
      GList *item_list;
      int i;

      /* **** IMPORTANT **** Check to see if retrieval succeeded  */
      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;
        }

      /* Print out the atoms we received */
      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_set_border_width (GTK_CONTAINER (window), 10);

      g_signal_connect (G_OBJECT (window), "destroy",
    	            G_CALLBACK (exit), NULL);

      /* Create a button the user can click to get targets */

      button = gtk_button_new_with_label ("Get Targets");
      gtk_container_add (GTK_CONTAINER (window), button);

      g_signal_connect (G_OBJECT (button), "clicked",
    		    G_CALLBACK (get_targets), (gpointer) window);
      g_signal_connect (G_OBJECT (window), "selection_received",
    		    G_CALLBACK (selection_received), NULL);

      gtk_widget_show (button);
      gtk_widget_show (window);

      gtk_main ();

      return 0;
    }

<<< Previous | Home | Next >>>
Managing Selections | Up | Supplying the selection