Blame gtk/gtktextbufferrichtext.c

Packit 98cdb6
/* gtkrichtext.c
Packit 98cdb6
 *
Packit 98cdb6
 * Copyright (C) 2006 Imendio AB
Packit 98cdb6
 * Contact: Michael Natterer <mitch@imendio.com>
Packit 98cdb6
 *
Packit 98cdb6
 * This library is free software; you can redistribute it and/or
Packit 98cdb6
 * modify it under the terms of the GNU Library General Public
Packit 98cdb6
 * License as published by the Free Software Foundation; either
Packit 98cdb6
 * version 2 of the License, or (at your option) any later version.
Packit 98cdb6
 *
Packit 98cdb6
 * This library is distributed in the hope that it will be useful,
Packit 98cdb6
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 98cdb6
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 98cdb6
 * Library General Public License for more details.
Packit 98cdb6
 *
Packit 98cdb6
 * You should have received a copy of the GNU Library General Public
Packit 98cdb6
 * License along with this library; if not, write to the
Packit 98cdb6
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Packit 98cdb6
 * Boston, MA 02111-1307, USA.
Packit 98cdb6
 */
Packit 98cdb6
Packit 98cdb6
#include "config.h"
Packit 98cdb6
Packit 98cdb6
#include <string.h>
Packit 98cdb6
Packit 98cdb6
#include "gtktextbufferrichtext.h"
Packit 98cdb6
#include "gtktextbufferserialize.h"
Packit 98cdb6
#include "gtkintl.h"
Packit 98cdb6
#include "gtkalias.h"
Packit 98cdb6
Packit 98cdb6
Packit 98cdb6
typedef struct
Packit 98cdb6
{
Packit 98cdb6
  gchar          *mime_type;
Packit 98cdb6
  gboolean        can_create_tags;
Packit 98cdb6
  GdkAtom         atom;
Packit 98cdb6
  gpointer        function;
Packit 98cdb6
  gpointer        user_data;
Packit 98cdb6
  GDestroyNotify  user_data_destroy;
Packit 98cdb6
} GtkRichTextFormat;
Packit 98cdb6
Packit 98cdb6
Packit 98cdb6
static GList   * register_format   (GList             *formats,
Packit 98cdb6
                                    const gchar       *mime_type,
Packit 98cdb6
                                    gpointer           function,
Packit 98cdb6
                                    gpointer           user_data,
Packit 98cdb6
                                    GDestroyNotify     user_data_destroy,
Packit 98cdb6
                                    GdkAtom           *atom);
Packit 98cdb6
static GList   * unregister_format (GList             *formats,
Packit 98cdb6
                                    GdkAtom            atom);
Packit 98cdb6
static GdkAtom * get_formats       (GList             *formats,
Packit 98cdb6
                                    gint              *n_formats);
Packit 98cdb6
static void      free_format       (GtkRichTextFormat *format);
Packit 98cdb6
static void      free_format_list  (GList             *formats);
Packit 98cdb6
static GQuark    serialize_quark   (void);
Packit 98cdb6
static GQuark    deserialize_quark (void);
Packit 98cdb6
Packit 98cdb6
Packit 98cdb6
/**
Packit 98cdb6
 * gtk_text_buffer_register_serialize_format:
Packit 98cdb6
 * @buffer: a #GtkTextBuffer
Packit 98cdb6
 * @mime_type: the format's mime-type
Packit 98cdb6
 * @function: the serialize function to register
Packit 98cdb6
 * @user_data: %function's user_data
Packit 98cdb6
 * @user_data_destroy: a function to call when @user_data is no longer needed
Packit 98cdb6
 *
Packit 98cdb6
 * This function registers a rich text serialization @function along with
Packit 98cdb6
 * its @mime_type with the passed @buffer.
Packit 98cdb6
 *
Packit 98cdb6
 * Return value: (transfer none): the #GdkAtom that corresponds to the
Packit 98cdb6
 *               newly registered format's mime-type.
Packit 98cdb6
 *
Packit 98cdb6
 * Since: 2.10
Packit 98cdb6
 **/
Packit 98cdb6
GdkAtom
Packit 98cdb6
gtk_text_buffer_register_serialize_format (GtkTextBuffer              *buffer,
Packit 98cdb6
                                           const gchar                *mime_type,
Packit 98cdb6
                                           GtkTextBufferSerializeFunc  function,
Packit 98cdb6
                                           gpointer                    user_data,
Packit 98cdb6
                                           GDestroyNotify              user_data_destroy)
Packit 98cdb6
{
Packit 98cdb6
  GList   *formats;
Packit 98cdb6
  GdkAtom  atom;
Packit 98cdb6
Packit 98cdb6
  g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), GDK_NONE);
Packit 98cdb6
  g_return_val_if_fail (mime_type != NULL && *mime_type != '\0', GDK_NONE);
Packit 98cdb6
  g_return_val_if_fail (function != NULL, GDK_NONE);
Packit 98cdb6
Packit 98cdb6
  formats = g_object_steal_qdata (G_OBJECT (buffer), serialize_quark ());
Packit 98cdb6
Packit 98cdb6
  formats = register_format (formats, mime_type,
Packit 98cdb6
                             (gpointer) function,
Packit 98cdb6
                             user_data, user_data_destroy,
Packit 98cdb6
                             &atom);
Packit 98cdb6
Packit 98cdb6
  g_object_set_qdata_full (G_OBJECT (buffer), serialize_quark (),
Packit 98cdb6
                           formats, (GDestroyNotify) free_format_list);
Packit 98cdb6
Packit 98cdb6
  g_object_notify (G_OBJECT (buffer), "copy-target-list");
Packit 98cdb6
Packit 98cdb6
  return atom;
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
/**
Packit 98cdb6
 * gtk_text_buffer_register_serialize_tagset:
Packit 98cdb6
 * @buffer: a #GtkTextBuffer
Packit 98cdb6
 * @tagset_name: (allow-none): an optional tagset name, on %NULL
Packit 98cdb6
 *
Packit 98cdb6
 * This function registers GTK+'s internal rich text serialization
Packit 98cdb6
 * format with the passed @buffer. The internal format does not comply
Packit 98cdb6
 * to any standard rich text format and only works between #GtkTextBuffer
Packit 98cdb6
 * instances. It is capable of serializing all of a text buffer's tags
Packit 98cdb6
 * and embedded pixbufs.
Packit 98cdb6
 *
Packit 98cdb6
 * This function is just a wrapper around
Packit 98cdb6
 * gtk_text_buffer_register_serialize_format(). The mime type used
Packit 98cdb6
 * for registering is "application/x-gtk-text-buffer-rich-text", or
Packit 98cdb6
 * "application/x-gtk-text-buffer-rich-text;format=@tagset_name" if a
Packit 98cdb6
 * @tagset_name was passed.
Packit 98cdb6
 *
Packit 98cdb6
 * The @tagset_name can be used to restrict the transfer of rich text
Packit 98cdb6
 * to buffers with compatible sets of tags, in order to avoid unknown
Packit 98cdb6
 * tags from being pasted. It is probably the common case to pass an
Packit 98cdb6
 * identifier != %NULL here, since the %NULL tagset requires the
Packit 98cdb6
 * receiving buffer to deal with with pasting of arbitrary tags.
Packit 98cdb6
 *
Packit 98cdb6
 * Return value: (transfer none): the #GdkAtom that corresponds to the
Packit 98cdb6
 *               newly registered format's mime-type.
Packit 98cdb6
 *
Packit 98cdb6
 * Since: 2.10
Packit 98cdb6
 **/
Packit 98cdb6
GdkAtom
Packit 98cdb6
gtk_text_buffer_register_serialize_tagset (GtkTextBuffer *buffer,
Packit 98cdb6
                                           const gchar   *tagset_name)
Packit 98cdb6
{
Packit 98cdb6
  gchar   *mime_type = "application/x-gtk-text-buffer-rich-text";
Packit 98cdb6
  GdkAtom  format;
Packit 98cdb6
Packit 98cdb6
  g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), GDK_NONE);
Packit 98cdb6
  g_return_val_if_fail (tagset_name == NULL || *tagset_name != '\0', GDK_NONE);
Packit 98cdb6
Packit 98cdb6
  if (tagset_name)
Packit 98cdb6
    mime_type =
Packit 98cdb6
      g_strdup_printf ("application/x-gtk-text-buffer-rich-text;format=%s",
Packit 98cdb6
                       tagset_name);
Packit 98cdb6
Packit 98cdb6
  format = gtk_text_buffer_register_serialize_format (buffer, mime_type,
Packit 98cdb6
                                                      _gtk_text_buffer_serialize_rich_text,
Packit 98cdb6
                                                      NULL, NULL);
Packit 98cdb6
Packit 98cdb6
  if (tagset_name)
Packit 98cdb6
    g_free (mime_type);
Packit 98cdb6
Packit 98cdb6
  return format;
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
/**
Packit 98cdb6
 * gtk_text_buffer_register_deserialize_format:
Packit 98cdb6
 * @buffer: a #GtkTextBuffer
Packit 98cdb6
 * @mime_type: the format's mime-type
Packit 98cdb6
 * @function: the deserialize function to register
Packit 98cdb6
 * @user_data: @function's user_data
Packit 98cdb6
 * @user_data_destroy: a function to call when @user_data is no longer needed
Packit 98cdb6
 *
Packit 98cdb6
 * This function registers a rich text deserialization @function along with
Packit 98cdb6
 * its @mime_type with the passed @buffer.
Packit 98cdb6
 *
Packit 98cdb6
 * Return value: (transfer none): the #GdkAtom that corresponds to the
Packit 98cdb6
 *               newly registered format's mime-type.
Packit 98cdb6
 *
Packit 98cdb6
 * Since: 2.10
Packit 98cdb6
 **/
Packit 98cdb6
GdkAtom
Packit 98cdb6
gtk_text_buffer_register_deserialize_format (GtkTextBuffer                *buffer,
Packit 98cdb6
                                             const gchar                  *mime_type,
Packit 98cdb6
                                             GtkTextBufferDeserializeFunc  function,
Packit 98cdb6
                                             gpointer                      user_data,
Packit 98cdb6
                                             GDestroyNotify                user_data_destroy)
Packit 98cdb6
{
Packit 98cdb6
  GList   *formats;
Packit 98cdb6
  GdkAtom  atom;
Packit 98cdb6
Packit 98cdb6
  g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), GDK_NONE);
Packit 98cdb6
  g_return_val_if_fail (mime_type != NULL && *mime_type != '\0', GDK_NONE);
Packit 98cdb6
  g_return_val_if_fail (function != NULL, GDK_NONE);
Packit 98cdb6
Packit 98cdb6
  formats = g_object_steal_qdata (G_OBJECT (buffer), deserialize_quark ());
Packit 98cdb6
Packit 98cdb6
  formats = register_format (formats, mime_type,
Packit 98cdb6
                             (gpointer) function,
Packit 98cdb6
                             user_data, user_data_destroy,
Packit 98cdb6
                             &atom);
Packit 98cdb6
Packit 98cdb6
  g_object_set_qdata_full (G_OBJECT (buffer), deserialize_quark (),
Packit 98cdb6
                           formats, (GDestroyNotify) free_format_list);
Packit 98cdb6
Packit 98cdb6
  g_object_notify (G_OBJECT (buffer), "paste-target-list");
Packit 98cdb6
Packit 98cdb6
  return atom;
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
/**
Packit 98cdb6
 * gtk_text_buffer_register_deserialize_tagset:
Packit 98cdb6
 * @buffer: a #GtkTextBuffer
Packit 98cdb6
 * @tagset_name: (allow-none): an optional tagset name, on %NULL
Packit 98cdb6
 *
Packit 98cdb6
 * This function registers GTK+'s internal rich text serialization
Packit 98cdb6
 * format with the passed @buffer. See
Packit 98cdb6
 * gtk_text_buffer_register_serialize_tagset() for details.
Packit 98cdb6
 *
Packit 98cdb6
 * Return value: (transfer none): the #GdkAtom that corresponds to the
Packit 98cdb6
 *               newly registered format's mime-type.
Packit 98cdb6
 *
Packit 98cdb6
 * Since: 2.10
Packit 98cdb6
 **/
Packit 98cdb6
GdkAtom
Packit 98cdb6
gtk_text_buffer_register_deserialize_tagset (GtkTextBuffer *buffer,
Packit 98cdb6
                                             const gchar   *tagset_name)
Packit 98cdb6
{
Packit 98cdb6
  gchar   *mime_type = "application/x-gtk-text-buffer-rich-text";
Packit 98cdb6
  GdkAtom  format;
Packit 98cdb6
Packit 98cdb6
  g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), GDK_NONE);
Packit 98cdb6
  g_return_val_if_fail (tagset_name == NULL || *tagset_name != '\0', GDK_NONE);
Packit 98cdb6
Packit 98cdb6
  if (tagset_name)
Packit 98cdb6
    mime_type =
Packit 98cdb6
      g_strdup_printf ("application/x-gtk-text-buffer-rich-text;format=%s",
Packit 98cdb6
                       tagset_name);
Packit 98cdb6
Packit 98cdb6
  format = gtk_text_buffer_register_deserialize_format (buffer, mime_type,
Packit 98cdb6
                                                        _gtk_text_buffer_deserialize_rich_text,
Packit 98cdb6
                                                        NULL, NULL);
Packit 98cdb6
Packit 98cdb6
  if (tagset_name)
Packit 98cdb6
    g_free (mime_type);
Packit 98cdb6
Packit 98cdb6
  return format;
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
/**
Packit 98cdb6
 * gtk_text_buffer_unregister_serialize_format:
Packit 98cdb6
 * @buffer: a #GtkTextBuffer
Packit 98cdb6
 * @format: a #GdkAtom representing a registered rich text format.
Packit 98cdb6
 *
Packit 98cdb6
 * This function unregisters a rich text format that was previously
Packit 98cdb6
 * registered using gtk_text_buffer_register_serialize_format() or
Packit 98cdb6
 * gtk_text_buffer_register_serialize_tagset()
Packit 98cdb6
 *
Packit 98cdb6
 * Since: 2.10
Packit 98cdb6
 **/
Packit 98cdb6
void
Packit 98cdb6
gtk_text_buffer_unregister_serialize_format (GtkTextBuffer *buffer,
Packit 98cdb6
                                             GdkAtom        format)
Packit 98cdb6
{
Packit 98cdb6
  GList *formats;
Packit 98cdb6
Packit 98cdb6
  g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
Packit 98cdb6
  g_return_if_fail (format != GDK_NONE);
Packit 98cdb6
Packit 98cdb6
  formats = g_object_steal_qdata (G_OBJECT (buffer), serialize_quark ());
Packit 98cdb6
Packit 98cdb6
  formats = unregister_format (formats, format);
Packit 98cdb6
Packit 98cdb6
  g_object_set_qdata_full (G_OBJECT (buffer), serialize_quark (),
Packit 98cdb6
                           formats, (GDestroyNotify) free_format_list);
Packit 98cdb6
Packit 98cdb6
  g_object_notify (G_OBJECT (buffer), "copy-target-list");
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
/**
Packit 98cdb6
 * gtk_text_buffer_unregister_deserialize_format:
Packit 98cdb6
 * @buffer: a #GtkTextBuffer
Packit 98cdb6
 * @format: a #GdkAtom representing a registered rich text format.
Packit 98cdb6
 *
Packit 98cdb6
 * This function unregisters a rich text format that was previously
Packit 98cdb6
 * registered using gtk_text_buffer_register_deserialize_format() or
Packit 98cdb6
 * gtk_text_buffer_register_deserialize_tagset().
Packit 98cdb6
 *
Packit 98cdb6
 * Since: 2.10
Packit 98cdb6
 **/
Packit 98cdb6
void
Packit 98cdb6
gtk_text_buffer_unregister_deserialize_format (GtkTextBuffer *buffer,
Packit 98cdb6
                                               GdkAtom        format)
Packit 98cdb6
{
Packit 98cdb6
  GList *formats;
Packit 98cdb6
Packit 98cdb6
  g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
Packit 98cdb6
  g_return_if_fail (format != GDK_NONE);
Packit 98cdb6
Packit 98cdb6
  formats = g_object_steal_qdata (G_OBJECT (buffer), deserialize_quark ());
Packit 98cdb6
Packit 98cdb6
  formats = unregister_format (formats, format);
Packit 98cdb6
Packit 98cdb6
  g_object_set_qdata_full (G_OBJECT (buffer), deserialize_quark (),
Packit 98cdb6
                           formats, (GDestroyNotify) free_format_list);
Packit 98cdb6
Packit 98cdb6
  g_object_notify (G_OBJECT (buffer), "paste-target-list");
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
/**
Packit 98cdb6
 * gtk_text_buffer_deserialize_set_can_create_tags:
Packit 98cdb6
 * @buffer: a #GtkTextBuffer
Packit 98cdb6
 * @format: a #GdkAtom representing a registered rich text format
Packit 98cdb6
 * @can_create_tags: whether deserializing this format may create tags
Packit 98cdb6
 *
Packit 98cdb6
 * Use this function to allow a rich text deserialization function to
Packit 98cdb6
 * create new tags in the receiving buffer. Note that using this
Packit 98cdb6
 * function is almost always a bad idea, because the rich text
Packit 98cdb6
 * functions you register should know how to map the rich text format
Packit 98cdb6
 * they handler to your text buffers set of tags.
Packit 98cdb6
 *
Packit 98cdb6
 * The ability of creating new (arbitrary!) tags in the receiving buffer
Packit 98cdb6
 * is meant for special rich text formats like the internal one that
Packit 98cdb6
 * is registered using gtk_text_buffer_register_deserialize_tagset(),
Packit 98cdb6
 * because that format is essentially a dump of the internal structure
Packit 98cdb6
 * of the source buffer, including its tag names.
Packit 98cdb6
 *
Packit 98cdb6
 * You should allow creation of tags only if you know what you are
Packit 98cdb6
 * doing, e.g. if you defined a tagset name for your application
Packit 98cdb6
 * suite's text buffers and you know that it's fine to receive new
Packit 98cdb6
 * tags from these buffers, because you know that your application can
Packit 98cdb6
 * handle the newly created tags.
Packit 98cdb6
 *
Packit 98cdb6
 * Since: 2.10
Packit 98cdb6
 **/
Packit 98cdb6
void
Packit 98cdb6
gtk_text_buffer_deserialize_set_can_create_tags (GtkTextBuffer *buffer,
Packit 98cdb6
                                                 GdkAtom        format,
Packit 98cdb6
                                                 gboolean       can_create_tags)
Packit 98cdb6
{
Packit 98cdb6
  GList *formats;
Packit 98cdb6
  GList *list;
Packit 98cdb6
  gchar *format_name;
Packit 98cdb6
Packit 98cdb6
  g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
Packit 98cdb6
  g_return_if_fail (format != GDK_NONE);
Packit 98cdb6
Packit 98cdb6
  formats = g_object_get_qdata (G_OBJECT (buffer), deserialize_quark ());
Packit 98cdb6
Packit 98cdb6
  for (list = formats; list; list = g_list_next (list))
Packit 98cdb6
    {
Packit 98cdb6
      GtkRichTextFormat *fmt = list->data;
Packit 98cdb6
Packit 98cdb6
      if (fmt->atom == format)
Packit 98cdb6
        {
Packit 98cdb6
          fmt->can_create_tags = can_create_tags ? TRUE : FALSE;
Packit 98cdb6
          return;
Packit 98cdb6
        }
Packit 98cdb6
    }
Packit 98cdb6
Packit 98cdb6
  format_name = gdk_atom_name (format);
Packit 98cdb6
  g_warning ("%s: \"%s\" is not registered as deserializable format "
Packit 98cdb6
             "with text buffer %p",
Packit 98cdb6
             G_STRFUNC, format_name ? format_name : "not a GdkAtom", buffer);
Packit 98cdb6
  g_free (format_name);
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
/**
Packit 98cdb6
 * gtk_text_buffer_deserialize_get_can_create_tags:
Packit 98cdb6
 * @buffer: a #GtkTextBuffer
Packit 98cdb6
 * @format: a #GdkAtom representing a registered rich text format
Packit 98cdb6
 *
Packit 98cdb6
 * This functions returns the value set with
Packit 98cdb6
 * gtk_text_buffer_deserialize_set_can_create_tags()
Packit 98cdb6
 *
Packit 98cdb6
 * Return value: whether deserializing this format may create tags
Packit 98cdb6
 *
Packit 98cdb6
 * Since: 2.10
Packit 98cdb6
 **/
Packit 98cdb6
gboolean
Packit 98cdb6
gtk_text_buffer_deserialize_get_can_create_tags (GtkTextBuffer *buffer,
Packit 98cdb6
                                                 GdkAtom        format)
Packit 98cdb6
{
Packit 98cdb6
  GList *formats;
Packit 98cdb6
  GList *list;
Packit 98cdb6
  gchar *format_name;
Packit 98cdb6
Packit 98cdb6
  g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), FALSE);
Packit 98cdb6
  g_return_val_if_fail (format != GDK_NONE, FALSE);
Packit 98cdb6
Packit 98cdb6
  formats = g_object_get_qdata (G_OBJECT (buffer), deserialize_quark ());
Packit 98cdb6
Packit 98cdb6
  for (list = formats; list; list = g_list_next (list))
Packit 98cdb6
    {
Packit 98cdb6
      GtkRichTextFormat *fmt = list->data;
Packit 98cdb6
Packit 98cdb6
      if (fmt->atom == format)
Packit 98cdb6
        {
Packit 98cdb6
          return fmt->can_create_tags;
Packit 98cdb6
        }
Packit 98cdb6
    }
Packit 98cdb6
Packit 98cdb6
  format_name = gdk_atom_name (format);
Packit 98cdb6
  g_warning ("%s: \"%s\" is not registered as deserializable format "
Packit 98cdb6
             "with text buffer %p",
Packit 98cdb6
             G_STRFUNC, format_name ? format_name : "not a GdkAtom", buffer);
Packit 98cdb6
  g_free (format_name);
Packit 98cdb6
Packit 98cdb6
  return FALSE;
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
/**
Packit 98cdb6
 * gtk_text_buffer_get_serialize_formats:
Packit 98cdb6
 * @buffer: a #GtkTextBuffer
Packit 98cdb6
 * @n_formats: return location for the number of formats
Packit 98cdb6
 *
Packit 98cdb6
 * This function returns the rich text serialize formats registered
Packit 98cdb6
 * with @buffer using gtk_text_buffer_register_serialize_format() or
Packit 98cdb6
 * gtk_text_buffer_register_serialize_tagset()
Packit 98cdb6
 *
Packit 98cdb6
 * Return value: (array length=n_formats) (transfer container): an array of
Packit 98cdb6
 *               #GdkAtoms representing the registered formats.
Packit 98cdb6
 *
Packit 98cdb6
 * Since: 2.10
Packit 98cdb6
 **/
Packit 98cdb6
GdkAtom *
Packit 98cdb6
gtk_text_buffer_get_serialize_formats (GtkTextBuffer *buffer,
Packit 98cdb6
                                       gint          *n_formats)
Packit 98cdb6
{
Packit 98cdb6
  GList *formats;
Packit 98cdb6
Packit 98cdb6
  g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
Packit 98cdb6
  g_return_val_if_fail (n_formats != NULL, NULL);
Packit 98cdb6
Packit 98cdb6
  formats = g_object_get_qdata (G_OBJECT (buffer), serialize_quark ());
Packit 98cdb6
Packit 98cdb6
  return get_formats (formats, n_formats);
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
/**
Packit 98cdb6
 * gtk_text_buffer_get_deserialize_formats:
Packit 98cdb6
 * @buffer: a #GtkTextBuffer
Packit 98cdb6
 * @n_formats: return location for the number of formats
Packit 98cdb6
 *
Packit 98cdb6
 * This function returns the rich text deserialize formats registered
Packit 98cdb6
 * with @buffer using gtk_text_buffer_register_deserialize_format() or
Packit 98cdb6
 * gtk_text_buffer_register_deserialize_tagset()
Packit 98cdb6
 *
Packit 98cdb6
 * Return value: (array length=n_formats) (transfer container): an array of
Packit 98cdb6
 *               #GdkAtoms representing the registered formats.
Packit 98cdb6
 *
Packit 98cdb6
 * Since: 2.10
Packit 98cdb6
 **/
Packit 98cdb6
GdkAtom *
Packit 98cdb6
gtk_text_buffer_get_deserialize_formats (GtkTextBuffer *buffer,
Packit 98cdb6
                                         gint          *n_formats)
Packit 98cdb6
{
Packit 98cdb6
  GList *formats;
Packit 98cdb6
Packit 98cdb6
  g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
Packit 98cdb6
  g_return_val_if_fail (n_formats != NULL, NULL);
Packit 98cdb6
Packit 98cdb6
  formats = g_object_get_qdata (G_OBJECT (buffer), deserialize_quark ());
Packit 98cdb6
Packit 98cdb6
  return get_formats (formats, n_formats);
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
/**
Packit 98cdb6
 * gtk_text_buffer_serialize:
Packit 98cdb6
 * @register_buffer: the #GtkTextBuffer @format is registered with
Packit 98cdb6
 * @content_buffer: the #GtkTextBuffer to serialize
Packit 98cdb6
 * @format: the rich text format to use for serializing
Packit 98cdb6
 * @start: start of block of text to serialize
Packit 98cdb6
 * @end: end of block of test to serialize
Packit 98cdb6
 * @length: return location for the length of the serialized data
Packit 98cdb6
 *
Packit 98cdb6
 * This function serializes the portion of text between @start
Packit 98cdb6
 * and @end in the rich text format represented by @format.
Packit 98cdb6
 *
Packit 98cdb6
 * @formats to be used must be registered using
Packit 98cdb6
 * gtk_text_buffer_register_serialize_format() or
Packit 98cdb6
 * gtk_text_buffer_register_serialize_tagset() beforehand.
Packit 98cdb6
 *
Packit 98cdb6
 * Return value: (array length=length) (transfer full): the serialized
Packit 98cdb6
 *               data, encoded as @format
Packit 98cdb6
 *
Packit 98cdb6
 * Since: 2.10
Packit 98cdb6
 **/
Packit 98cdb6
guint8 *
Packit 98cdb6
gtk_text_buffer_serialize (GtkTextBuffer     *register_buffer,
Packit 98cdb6
                           GtkTextBuffer     *content_buffer,
Packit 98cdb6
                           GdkAtom            format,
Packit 98cdb6
                           const GtkTextIter *start,
Packit 98cdb6
                           const GtkTextIter *end,
Packit 98cdb6
                           gsize             *length)
Packit 98cdb6
{
Packit 98cdb6
  GList *formats;
Packit 98cdb6
  GList *list;
Packit 98cdb6
Packit 98cdb6
  g_return_val_if_fail (GTK_IS_TEXT_BUFFER (register_buffer), NULL);
Packit 98cdb6
  g_return_val_if_fail (GTK_IS_TEXT_BUFFER (content_buffer), NULL);
Packit 98cdb6
  g_return_val_if_fail (format != GDK_NONE, NULL);
Packit 98cdb6
  g_return_val_if_fail (start != NULL, NULL);
Packit 98cdb6
  g_return_val_if_fail (end != NULL, NULL);
Packit 98cdb6
  g_return_val_if_fail (length != NULL, NULL);
Packit 98cdb6
Packit 98cdb6
  *length = 0;
Packit 98cdb6
Packit 98cdb6
  formats = g_object_get_qdata (G_OBJECT (register_buffer),
Packit 98cdb6
                                serialize_quark ());
Packit 98cdb6
Packit 98cdb6
  for (list = formats; list; list = g_list_next (list))
Packit 98cdb6
    {
Packit 98cdb6
      GtkRichTextFormat *fmt = list->data;
Packit 98cdb6
Packit 98cdb6
      if (fmt->atom == format)
Packit 98cdb6
        {
Packit 98cdb6
          GtkTextBufferSerializeFunc function = fmt->function;
Packit 98cdb6
Packit 98cdb6
          return function (register_buffer, content_buffer,
Packit 98cdb6
                           start, end, length, fmt->user_data);
Packit 98cdb6
        }
Packit 98cdb6
    }
Packit 98cdb6
Packit 98cdb6
  return NULL;
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
/**
Packit 98cdb6
 * gtk_text_buffer_deserialize:
Packit 98cdb6
 * @register_buffer: the #GtkTextBuffer @format is registered with
Packit 98cdb6
 * @content_buffer: the #GtkTextBuffer to deserialize into
Packit 98cdb6
 * @format: the rich text format to use for deserializing
Packit 98cdb6
 * @iter: insertion point for the deserialized text
Packit 98cdb6
 * @data: (array length=length): data to deserialize
Packit 98cdb6
 * @length: length of @data
Packit 98cdb6
 * @error: return location for a #GError
Packit 98cdb6
 *
Packit 98cdb6
 * This function deserializes rich text in format @format and inserts
Packit 98cdb6
 * it at @iter.
Packit 98cdb6
 *
Packit 98cdb6
 * @formats to be used must be registered using
Packit 98cdb6
 * gtk_text_buffer_register_deserialize_format() or
Packit 98cdb6
 * gtk_text_buffer_register_deserialize_tagset() beforehand.
Packit 98cdb6
 *
Packit 98cdb6
 * Return value: %TRUE on success, %FALSE otherwise.
Packit 98cdb6
 *
Packit 98cdb6
 * Since: 2.10
Packit 98cdb6
 **/
Packit 98cdb6
gboolean
Packit 98cdb6
gtk_text_buffer_deserialize (GtkTextBuffer  *register_buffer,
Packit 98cdb6
                             GtkTextBuffer  *content_buffer,
Packit 98cdb6
                             GdkAtom         format,
Packit 98cdb6
                             GtkTextIter    *iter,
Packit 98cdb6
                             const guint8   *data,
Packit 98cdb6
                             gsize           length,
Packit 98cdb6
                             GError        **error)
Packit 98cdb6
{
Packit 98cdb6
  GList    *formats;
Packit 98cdb6
  GList    *list;
Packit 98cdb6
Packit 98cdb6
  g_return_val_if_fail (GTK_IS_TEXT_BUFFER (register_buffer), FALSE);
Packit 98cdb6
  g_return_val_if_fail (GTK_IS_TEXT_BUFFER (content_buffer), FALSE);
Packit 98cdb6
  g_return_val_if_fail (format != GDK_NONE, FALSE);
Packit 98cdb6
  g_return_val_if_fail (iter != NULL, FALSE);
Packit 98cdb6
  g_return_val_if_fail (data != NULL, FALSE);
Packit 98cdb6
  g_return_val_if_fail (length > 0, FALSE);
Packit 98cdb6
  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
Packit 98cdb6
Packit 98cdb6
  formats = g_object_get_qdata (G_OBJECT (register_buffer),
Packit 98cdb6
                                deserialize_quark ());
Packit 98cdb6
Packit 98cdb6
  for (list = formats; list; list = g_list_next (list))
Packit 98cdb6
    {
Packit 98cdb6
      GtkRichTextFormat *fmt = list->data;
Packit 98cdb6
Packit 98cdb6
      if (fmt->atom == format)
Packit 98cdb6
        {
Packit 98cdb6
          GtkTextBufferDeserializeFunc function = fmt->function;
Packit 98cdb6
          gboolean                     success;
Packit 98cdb6
          GSList                      *split_tags;
Packit 98cdb6
          GSList                      *list;
Packit 98cdb6
          GtkTextMark                 *left_end        = NULL;
Packit 98cdb6
          GtkTextMark                 *right_start     = NULL;
Packit 98cdb6
          GSList                      *left_start_list = NULL;
Packit 98cdb6
          GSList                      *right_end_list  = NULL;
Packit 98cdb6
Packit 98cdb6
          /*  We don't want the tags that are effective at the insertion
Packit 98cdb6
           *  point to affect the pasted text, therefore we remove and
Packit 98cdb6
           *  remember them, so they can be re-applied left and right of
Packit 98cdb6
           *  the inserted text after pasting
Packit 98cdb6
           */
Packit 98cdb6
          split_tags = gtk_text_iter_get_tags (iter);
Packit 98cdb6
Packit 98cdb6
          list = split_tags;
Packit 98cdb6
          while (list)
Packit 98cdb6
            {
Packit 98cdb6
              GtkTextTag *tag = list->data;
Packit 98cdb6
Packit 98cdb6
              list = g_slist_next (list);
Packit 98cdb6
Packit 98cdb6
              /*  If a tag begins at the insertion point, ignore it
Packit 98cdb6
               *  because it doesn't affect the pasted text
Packit 98cdb6
               */
Packit 98cdb6
              if (gtk_text_iter_begins_tag (iter, tag))
Packit 98cdb6
                split_tags = g_slist_remove (split_tags, tag);
Packit 98cdb6
            }
Packit 98cdb6
Packit 98cdb6
          if (split_tags)
Packit 98cdb6
            {
Packit 98cdb6
              /*  Need to remember text marks, because text iters
Packit 98cdb6
               *  don't survive pasting
Packit 98cdb6
               */
Packit 98cdb6
              left_end = gtk_text_buffer_create_mark (content_buffer,
Packit 98cdb6
                                                      NULL, iter, TRUE);
Packit 98cdb6
              right_start = gtk_text_buffer_create_mark (content_buffer,
Packit 98cdb6
                                                         NULL, iter, FALSE);
Packit 98cdb6
Packit 98cdb6
              for (list = split_tags; list; list = g_slist_next (list))
Packit 98cdb6
                {
Packit 98cdb6
                  GtkTextTag  *tag             = list->data;
Packit 98cdb6
                  GtkTextIter *backward_toggle = gtk_text_iter_copy (iter);
Packit 98cdb6
                  GtkTextIter *forward_toggle  = gtk_text_iter_copy (iter);
Packit 98cdb6
                  GtkTextMark *left_start      = NULL;
Packit 98cdb6
                  GtkTextMark *right_end       = NULL;
Packit 98cdb6
Packit 98cdb6
                  gtk_text_iter_backward_to_tag_toggle (backward_toggle, tag);
Packit 98cdb6
                  left_start = gtk_text_buffer_create_mark (content_buffer,
Packit 98cdb6
                                                            NULL,
Packit 98cdb6
                                                            backward_toggle,
Packit 98cdb6
                                                            FALSE);
Packit 98cdb6
Packit 98cdb6
                  gtk_text_iter_forward_to_tag_toggle (forward_toggle, tag);
Packit 98cdb6
                  right_end = gtk_text_buffer_create_mark (content_buffer,
Packit 98cdb6
                                                           NULL,
Packit 98cdb6
                                                           forward_toggle,
Packit 98cdb6
                                                           TRUE);
Packit 98cdb6
Packit 98cdb6
                  left_start_list = g_slist_prepend (left_start_list, left_start);
Packit 98cdb6
                  right_end_list = g_slist_prepend (right_end_list, right_end);
Packit 98cdb6
Packit 98cdb6
                  gtk_text_buffer_remove_tag (content_buffer, tag,
Packit 98cdb6
                                              backward_toggle,
Packit 98cdb6
                                              forward_toggle);
Packit 98cdb6
Packit 98cdb6
                  gtk_text_iter_free (forward_toggle);
Packit 98cdb6
                  gtk_text_iter_free (backward_toggle);
Packit 98cdb6
                }
Packit 98cdb6
Packit 98cdb6
              left_start_list = g_slist_reverse (left_start_list);
Packit 98cdb6
              right_end_list = g_slist_reverse (right_end_list);
Packit 98cdb6
            }
Packit 98cdb6
Packit 98cdb6
          success = function (register_buffer, content_buffer,
Packit 98cdb6
                              iter, data, length,
Packit 98cdb6
                              fmt->can_create_tags,
Packit 98cdb6
                              fmt->user_data,
Packit 98cdb6
                              error);
Packit 98cdb6
Packit 98cdb6
          if (!success && error != NULL && *error == NULL)
Packit 98cdb6
            g_set_error (error, 0, 0,
Packit 98cdb6
                         _("Unknown error when trying to deserialize %s"),
Packit 98cdb6
                         gdk_atom_name (format));
Packit 98cdb6
Packit 98cdb6
          if (split_tags)
Packit 98cdb6
            {
Packit 98cdb6
              GSList      *left_list;
Packit 98cdb6
              GSList      *right_list;
Packit 98cdb6
              GtkTextIter  left_e;
Packit 98cdb6
              GtkTextIter  right_s;
Packit 98cdb6
Packit 98cdb6
              /*  Turn the remembered marks back into iters so they
Packit 98cdb6
               *  can by used to re-apply the remembered tags
Packit 98cdb6
               */
Packit 98cdb6
              gtk_text_buffer_get_iter_at_mark (content_buffer,
Packit 98cdb6
                                                &left_e, left_end);
Packit 98cdb6
              gtk_text_buffer_get_iter_at_mark (content_buffer,
Packit 98cdb6
                                                &right_s, right_start);
Packit 98cdb6
Packit 98cdb6
              for (list = split_tags,
Packit 98cdb6
                     left_list = left_start_list,
Packit 98cdb6
                     right_list = right_end_list;
Packit 98cdb6
                   list && left_list && right_list;
Packit 98cdb6
                   list = g_slist_next (list),
Packit 98cdb6
                     left_list = g_slist_next (left_list),
Packit 98cdb6
                     right_list = g_slist_next (right_list))
Packit 98cdb6
                {
Packit 98cdb6
                  GtkTextTag  *tag        = list->data;
Packit 98cdb6
                  GtkTextMark *left_start = left_list->data;
Packit 98cdb6
                  GtkTextMark *right_end  = right_list->data;
Packit 98cdb6
                  GtkTextIter  left_s;
Packit 98cdb6
                  GtkTextIter  right_e;
Packit 98cdb6
Packit 98cdb6
                  gtk_text_buffer_get_iter_at_mark (content_buffer,
Packit 98cdb6
                                                    &left_s, left_start);
Packit 98cdb6
                  gtk_text_buffer_get_iter_at_mark (content_buffer,
Packit 98cdb6
                                                    &right_e, right_end);
Packit 98cdb6
Packit 98cdb6
                  gtk_text_buffer_apply_tag (content_buffer, tag,
Packit 98cdb6
                                             &left_s, &left_e);
Packit 98cdb6
                  gtk_text_buffer_apply_tag (content_buffer, tag,
Packit 98cdb6
                                             &right_s, &right_e);
Packit 98cdb6
Packit 98cdb6
                  gtk_text_buffer_delete_mark (content_buffer, left_start);
Packit 98cdb6
                  gtk_text_buffer_delete_mark (content_buffer, right_end);
Packit 98cdb6
                }
Packit 98cdb6
Packit 98cdb6
              gtk_text_buffer_delete_mark (content_buffer, left_end);
Packit 98cdb6
              gtk_text_buffer_delete_mark (content_buffer, right_start);
Packit 98cdb6
Packit 98cdb6
              g_slist_free (split_tags);
Packit 98cdb6
              g_slist_free (left_start_list);
Packit 98cdb6
              g_slist_free (right_end_list);
Packit 98cdb6
            }
Packit 98cdb6
Packit 98cdb6
          return success;
Packit 98cdb6
        }
Packit 98cdb6
    }
Packit 98cdb6
Packit 98cdb6
  g_set_error (error, 0, 0,
Packit 98cdb6
               _("No deserialize function found for format %s"),
Packit 98cdb6
               gdk_atom_name (format));
Packit 98cdb6
Packit 98cdb6
  return FALSE;
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
Packit 98cdb6
/*  private functions  */
Packit 98cdb6
Packit 98cdb6
static GList *
Packit 98cdb6
register_format (GList          *formats,
Packit 98cdb6
                 const gchar    *mime_type,
Packit 98cdb6
                 gpointer        function,
Packit 98cdb6
                 gpointer        user_data,
Packit 98cdb6
                 GDestroyNotify  user_data_destroy,
Packit 98cdb6
                 GdkAtom        *atom)
Packit 98cdb6
{
Packit 98cdb6
  GtkRichTextFormat *format;
Packit 98cdb6
Packit 98cdb6
  *atom = gdk_atom_intern (mime_type, FALSE);
Packit 98cdb6
Packit 98cdb6
  formats = unregister_format (formats, *atom);
Packit 98cdb6
Packit 98cdb6
  format = g_new0 (GtkRichTextFormat, 1);
Packit 98cdb6
Packit 98cdb6
  format->mime_type         = g_strdup (mime_type);
Packit 98cdb6
  format->can_create_tags   = FALSE;
Packit 98cdb6
  format->atom              = *atom;
Packit 98cdb6
  format->function          = function;
Packit 98cdb6
  format->user_data         = user_data;
Packit 98cdb6
  format->user_data_destroy = user_data_destroy;
Packit 98cdb6
Packit 98cdb6
  return g_list_append (formats, format);
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
static GList *
Packit 98cdb6
unregister_format (GList   *formats,
Packit 98cdb6
                   GdkAtom  atom)
Packit 98cdb6
{
Packit 98cdb6
  GList *list;
Packit 98cdb6
Packit 98cdb6
  for (list = formats; list; list = g_list_next (list))
Packit 98cdb6
    {
Packit 98cdb6
      GtkRichTextFormat *format = list->data;
Packit 98cdb6
Packit 98cdb6
      if (format->atom == atom)
Packit 98cdb6
        {
Packit 98cdb6
          free_format (format);
Packit 98cdb6
Packit 98cdb6
          return g_list_delete_link (formats, list);
Packit 98cdb6
        }
Packit 98cdb6
    }
Packit 98cdb6
Packit 98cdb6
  return formats;
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
static GdkAtom *
Packit 98cdb6
get_formats (GList *formats,
Packit 98cdb6
             gint  *n_formats)
Packit 98cdb6
{
Packit 98cdb6
  GdkAtom *array;
Packit 98cdb6
  GList   *list;
Packit 98cdb6
  gint     i;
Packit 98cdb6
Packit 98cdb6
  *n_formats = g_list_length (formats);
Packit 98cdb6
  array = g_new0 (GdkAtom, *n_formats);
Packit 98cdb6
Packit 98cdb6
  for (list = formats, i = 0; list; list = g_list_next (list), i++)
Packit 98cdb6
    {
Packit 98cdb6
      GtkRichTextFormat *format = list->data;
Packit 98cdb6
Packit 98cdb6
      array[i] = format->atom;
Packit 98cdb6
    }
Packit 98cdb6
Packit 98cdb6
  return array;
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
static void
Packit 98cdb6
free_format (GtkRichTextFormat *format)
Packit 98cdb6
{
Packit 98cdb6
  if (format->user_data_destroy)
Packit 98cdb6
    format->user_data_destroy (format->user_data);
Packit 98cdb6
Packit 98cdb6
  g_free (format->mime_type);
Packit 98cdb6
  g_free (format);
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
static void
Packit 98cdb6
free_format_list (GList *formats)
Packit 98cdb6
{
Packit 98cdb6
  g_list_foreach (formats, (GFunc) free_format, NULL);
Packit 98cdb6
  g_list_free (formats);
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
static GQuark
Packit 98cdb6
serialize_quark (void)
Packit 98cdb6
{
Packit 98cdb6
  static GQuark quark = 0;
Packit 98cdb6
Packit 98cdb6
  if (! quark)
Packit 98cdb6
    quark = g_quark_from_static_string ("gtk-text-buffer-serialize-formats");
Packit 98cdb6
Packit 98cdb6
  return quark;
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
static GQuark
Packit 98cdb6
deserialize_quark (void)
Packit 98cdb6
{
Packit 98cdb6
  static GQuark quark = 0;
Packit 98cdb6
Packit 98cdb6
  if (! quark)
Packit 98cdb6
    quark = g_quark_from_static_string ("gtk-text-buffer-deserialize-formats");
Packit 98cdb6
Packit 98cdb6
  return quark;
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
#define __GTK_TEXT_BUFFER_RICH_TEXT_C__
Packit 98cdb6
#include "gtkaliasdef.c"