"Neil Hodgson" <neilh@hare.net.au> writes:

> When cutting and copying in my application, I'd like to be able to
> include the data in both standard string format and an application specific
> format. On MacOS or Windows you open the clipboard and add one format and
> then the other. I looked at the gtk_selection API and even read the
> implementation but could not work out how to do this. Reading the
> implementation of gtk_selection_data_set shows that it can't be called twice
> as the second call overwrites the first.
>
> So, thinking 'Gnumeric must be able to do this' I downloaded Gnumeric's
> source only to find that it doesn't - it uses rich copy and paste (formulas,
> styling and values) internally and renders to text for other apps, including
> other instances of Gnumeric.
>
> Does anyone know how to solve this or work around it? I've thought of
> adding the application specific format after a \0 but haven't tried it yet.

The thing to realize here is that the way the X clipboard works,
you don't store data onto the clipboard at all, what you do
is say that you are willing to provide the data and at that
point you can list all the types you can provide. Then the
requestor asks you for a particular format.

We can see an example of this in gtkeditable.c, though it isn't
perhaps the clearest example:

  static const GtkTargetEntry targets[] = {
    { "STRING", 0, TARGET_STRING },
    { "TEXT", 0, TARGET_TEXT },
    { "COMPOUND_TEXT", 0, TARGET_COMPOUND_TEXT }
  };
  static const gint n_targets = sizeof(targets) / sizeof(targets[0]);

  if (!clipboard_atom)
    clipboard_atom = gdk_atom_intern ("CLIPBOARD", FALSE);

  gtk_selection_add_targets (GTK_WIDGET (editable), clipboard_atom,
                             targets, n_targets);

This says "when the widget 'editable' becomes the owner of the
clipboard selection", it can convert the selection into the
three targets, "STRING", "TEXT", and "COMPOUND_TEXT". The
third element in the GtkTargetEntry structure is a arbitrary
integer that gets passed back to your "selection_get" callback.
We use it here to identify the different target types.

The ::selection_get handler then looks like;

static void
gtk_editable_selection_get (GtkWidget *widget,
                            GtkSelectionData *selection_data,
                            guint info,
                            guint time)
{
[...]

  if (info == TARGET_STRING)
    {
      gtk_selection_data_set (selection_data,
                              GDK_SELECTION_TYPE_STRING,
                              8*sizeof(gchar), (guchar *)str, length);
    }
  else if ((info == TARGET_TEXT) || (info == TARGET_COMPOUND_TEXT))
    {
      guchar *text;
      gchar c;
      GdkAtom encoding;
      gint format;
      gint new_length;

      c = str[length];
      str[length] = '\0';
      gdk_string_to_compound_text (str, &encoding, &format, &text, &new_length);
      gtk_selection_data_set (selection_data, encoding, format, text, new_length);
      gdk_free_compound_text (text);
      str[length] = c;
    }

Someone who wants to get the data from the clipboard can either
just try to retrieve a particular target and see if that succeeds,
or alternatively, they can retrieve the special TARGETS target
which is a list of all available targets. There is an example
of this in gtk+/gtk/testselection.c.

For more information, see the selections section of the GTK+ tutorial
(which is a bit out of date), the file gtk+/doc/Changes-1.2.txt, which
explains how things have changed, and the X ICCCM for general
information about selections in X.

Regards,
					Owen
