Index: gtk/gtk.symbols
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtk.symbols,v
retrieving revision 1.80
diff -u -p -b -r1.80 gtk.symbols
--- gtk/gtk.symbols	18 Jan 2006 22:39:13 -0000	1.80
+++ gtk/gtk.symbols	19 Jan 2006 15:08:56 -0000
@@ -2670,6 +2670,7 @@ gtk_target_list_add_table
 gtk_target_list_add_text_targets
 gtk_target_list_add_uri_targets
 gtk_target_list_find
+gtk_target_list_get_type
 gtk_target_list_new
 gtk_target_list_ref
 gtk_target_list_remove
@@ -2911,6 +2912,7 @@ gtk_text_buffer_delete_mark_by_name
 gtk_text_buffer_delete_selection
 gtk_text_buffer_end_user_action
 gtk_text_buffer_get_bounds
+gtk_text_buffer_get_can_transfer_rich_text
 gtk_text_buffer_get_char_count
 gtk_text_buffer_get_end_iter
 gtk_text_buffer_get_has_selection
@@ -2924,6 +2926,8 @@ gtk_text_buffer_get_iter_at_offset
 gtk_text_buffer_get_line_count
 gtk_text_buffer_get_mark
 gtk_text_buffer_get_modified
+gtk_text_buffer_get_rich_text_atom
+gtk_text_buffer_get_rich_text_format
 gtk_text_buffer_get_selection_bound
 gtk_text_buffer_get_selection_bounds
 gtk_text_buffer_get_slice
@@ -2951,7 +2955,9 @@ gtk_text_buffer_remove_selection_clipboa
 gtk_text_buffer_remove_tag
 gtk_text_buffer_remove_tag_by_name
 gtk_text_buffer_select_range
+gtk_text_buffer_set_can_transfer_rich_text
 gtk_text_buffer_set_modified
+gtk_text_buffer_set_rich_text_format
 gtk_text_buffer_set_text
 #endif
 #endif
Index: gtk/gtktextbuffer.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtktextbuffer.c,v
retrieving revision 1.109
diff -u -p -b -r1.109 gtktextbuffer.c
--- gtk/gtktextbuffer.c	9 Dec 2005 17:26:26 -0000	1.109
+++ gtk/gtktextbuffer.c	19 Jan 2006 15:08:57 -0000
@@ -1,5 +1,6 @@
 /* GTK - The GIMP Toolkit
  * gtktextbuffer.c Copyright (C) 2000 Red Hat, Inc.
+ *                 Copyright (C) 2004 Nokia Corporation
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -24,17 +25,17 @@
  * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
  */
 
-
 #include <config.h>
 #include <string.h>
 #include <stdarg.h>
 
-
 #define GTK_TEXT_USE_INTERNAL_UNSUPPORTED_API
 #include "gtkclipboard.h"
+#include "gtkdnd.h"
 #include "gtkinvisible.h"
 #include "gtkmarshalers.h"
 #include "gtktextbuffer.h"
+#include "gtktextbufferserialize.h"
 #include "gtktextbtree.h"
 #include "gtktextiterprivate.h"
 #include "gtkprivate.h"
@@ -42,6 +43,24 @@
 #include "gtkalias.h"
 
 
+#define GTK_TEXT_BUFFER_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_TEXT_BUFFER, GtkTextBufferPrivate))
+
+typedef struct _GtkTextBufferPrivate GtkTextBufferPrivate;
+
+struct _GtkTextBufferPrivate
+{
+  GtkTargetList  *target_list;
+
+  GtkTargetEntry *target_entries;
+  gint            n_target_entries;
+
+  gboolean        can_transfer_rich_text;
+  gchar          *rich_text_format;
+
+  GdkAtom         rich_text_atom;
+};
+
+
 typedef struct _ClipboardRequest ClipboardRequest;
 
 struct _ClipboardRequest
@@ -77,15 +96,16 @@ enum {
   
   /* Normal */
   PROP_TEXT,
-  PROP_HAS_SELECTION
+  PROP_HAS_SELECTION,
+  PROP_TARGET_LIST,
+  PROP_CAN_TRANSFER_RICH_TEXT,
+  PROP_RICH_TEXT_FORMAT
 };
 
 enum {
-  TARGET_STRING,
   TARGET_TEXT,
-  TARGET_COMPOUND_TEXT,
-  TARGET_UTF8_STRING,
-  TARGET_TEXT_BUFFER_CONTENTS
+  TARGET_RICH_TEXT,
+  TARGET_BUFFER_CONTENTS
 };
 
 static void gtk_text_buffer_init       (GtkTextBuffer      *tkxt_buffer);
@@ -127,6 +147,8 @@ static void update_selection_clipboards 
 
 static GtkTextBuffer *create_clipboard_contents_buffer (GtkTextBuffer *buffer);
 
+static void gtk_text_buffer_free_target_list      (GtkTextBuffer *buffer);
+
 static GObjectClass *parent_class = NULL;
 static guint signals[LAST_SIGNAL] = { 0 };
 
@@ -227,7 +249,52 @@ gtk_text_buffer_class_init (GtkTextBuffe
                                                          P_("Has selection"),
                                                          P_("Whether the buffer has some text currently selected"),
                                                          FALSE,
-                                                         G_PARAM_READABLE));
+                                                         GTK_PARAM_READABLE));
+
+  /**
+   * GtkTextBuffer:target-list:
+   *
+   * The list of targets this buffer supports for clipboard and DND transfer.
+   *
+   * Since: 2.10
+   */
+  g_object_class_install_property (object_class,
+                                   PROP_TARGET_LIST,
+                                   g_param_spec_boxed ("target-list",
+                                                       P_("Target list"),
+                                                       P_("The list of targets this buffer supports for clipboard and DND transfer"),
+                                                       GTK_TYPE_TARGET_LIST,
+                                                       GTK_PARAM_READABLE));
+
+  /**
+   * GtkTextBuffer:can-transfer-rich-text:
+   *
+   * Whether rich text can be pasted or dropped to the buffer.
+   *
+   * Since: 2.10
+   */
+  g_object_class_install_property (object_class,
+                                   PROP_CAN_TRANSFER_RICH_TEXT,
+                                   g_param_spec_boolean ("can-transfer-rich-text",
+                                                         P_("Can transfer rich text"),
+                                                         P_("Whether it should be possible to paste or drop rich text to the buffer"),
+                                                         FALSE,
+                                                         GTK_PARAM_READWRITE));
+
+  /**
+   * GtkTextBuffer:rich-text-format:
+   *
+   * Name of a collection of tags that the text view supports.
+   *
+   * Since: 2.10
+   */
+  g_object_class_install_property (object_class,
+                                   PROP_RICH_TEXT_FORMAT,
+                                   g_param_spec_string ("rich-text-format",
+                                                        P_("Rich Text Format"),
+                                                        P_("Name of a collection of tags that the text view supports"),
+                                                        NULL,
+                                                        GTK_PARAM_READWRITE));
 
   signals[INSERT_TEXT] =
     g_signal_new (I_("insert_text"),
@@ -379,13 +446,19 @@ gtk_text_buffer_class_init (GtkTextBuffe
                   _gtk_marshal_VOID__VOID,
                   G_TYPE_NONE,
                   0);  
+
+  g_type_class_add_private (object_class, sizeof (GtkTextBufferPrivate));
 }
 
 static void
 gtk_text_buffer_init (GtkTextBuffer *buffer)
 {
+  GtkTextBufferPrivate *priv = GTK_TEXT_BUFFER_GET_PRIVATE (buffer);
+
   buffer->clipboard_contents_buffers = NULL;
   buffer->tag_table = NULL;
+
+  priv->rich_text_atom = gdk_atom_intern_static_string ("application/x-gtk-text-view-rich-text");
 }
 
 static void
@@ -434,6 +507,16 @@ gtk_text_buffer_set_property (GObject   
 				g_value_get_string (value), -1);
       break;
 
+    case PROP_CAN_TRANSFER_RICH_TEXT:
+      gtk_text_buffer_set_can_transfer_rich_text (text_buffer,
+                                                  g_value_get_boolean (value));
+      break;
+
+    case PROP_RICH_TEXT_FORMAT:
+      gtk_text_buffer_set_rich_text_format (text_buffer,
+                                            g_value_get_string (value));
+      break;
+
     default:
       break;
     }
@@ -463,7 +546,8 @@ gtk_text_buffer_get_property (GObject   
       gtk_text_buffer_get_end_iter (text_buffer, &end);
 	    
       g_value_set_string (value,
-			  gtk_text_buffer_get_text (text_buffer, &start, &end, FALSE));
+                            gtk_text_buffer_get_text (text_buffer,
+                                                      &start, &end, FALSE));
       break;
     }
 
@@ -471,6 +555,20 @@ gtk_text_buffer_get_property (GObject   
       g_value_set_boolean (value, text_buffer->has_selection);
       break;
 
+    case PROP_TARGET_LIST:
+      g_value_set_boxed (value, gtk_text_buffer_get_target_list (text_buffer));
+      break;
+
+    case PROP_CAN_TRANSFER_RICH_TEXT:
+      g_value_set_boolean (value,
+                           gtk_text_buffer_get_can_transfer_rich_text (text_buffer));
+      break;
+
+    case PROP_RICH_TEXT_FORMAT:
+      g_value_set_string (value,
+                          gtk_text_buffer_get_rich_text_format (text_buffer));
+      break;
+
     default:
       break;
     }
@@ -498,11 +596,14 @@ static void
 gtk_text_buffer_finalize (GObject *object)
 {
   GtkTextBuffer *buffer;
+  GtkTextBufferPrivate *priv;
 
   buffer = GTK_TEXT_BUFFER (object);
 
   remove_all_selection_clipboards (buffer);
 
+  priv = GTK_TEXT_BUFFER_GET_PRIVATE (buffer);
+
   if (buffer->tag_table)
     {
       _gtk_text_tag_table_remove_buffer (buffer->tag_table, buffer);
@@ -521,6 +622,11 @@ gtk_text_buffer_finalize (GObject *objec
 
   buffer->log_attr_cache = NULL;
   
+  if (priv->target_list)
+    gtk_text_buffer_free_target_list (buffer);
+
+  g_free (priv->rich_text_format);
+
   G_OBJECT_CLASS (parent_class)->finalize (object);
 }
 
@@ -2836,12 +2942,12 @@ clipboard_get_selection_cb (GtkClipboard
                             gpointer          data)
 {
   GtkTextBuffer *buffer = GTK_TEXT_BUFFER (data);
+  GtkTextBufferPrivate *priv = GTK_TEXT_BUFFER_GET_PRIVATE (buffer);
   GtkTextIter start, end;
 
   if (gtk_text_buffer_get_selection_bounds (buffer, &start, &end))
     {
-      if (selection_data->target ==
-          gdk_atom_intern_static_string ("GTK_TEXT_BUFFER_CONTENTS"))
+      if (info == TARGET_BUFFER_CONTENTS)
         {
           /* Provide the address of the buffer; this will only be
            * used within-process
@@ -2852,6 +2958,20 @@ clipboard_get_selection_cb (GtkClipboard
                                   (void*)&buffer,
                                   sizeof (buffer));
         }
+      else if (info == TARGET_RICH_TEXT)
+        {
+          gchar *str;
+          gint len;
+
+          str = _gtk_text_buffer_serialize_rich_text (buffer, &start, &end,
+                                                      &len);
+
+          gtk_selection_data_set (selection_data,
+                                  priv->rich_text_atom,
+                                  8, /* bytes */
+                                  str, len);
+          g_free (str);
+        }
       else
         {
           gchar *str;
@@ -2866,11 +2986,18 @@ clipboard_get_selection_cb (GtkClipboard
 static GtkTextBuffer *
 create_clipboard_contents_buffer (GtkTextBuffer *buffer)
 {
+  GtkTextBufferPrivate *priv = GTK_TEXT_BUFFER_GET_PRIVATE (buffer);
   GtkTextBuffer *contents;
 
   contents = gtk_text_buffer_new (gtk_text_buffer_get_tag_table (buffer));
 
-  g_object_set_data (G_OBJECT (contents), I_("gtk-text-buffer-clipboard"), GINT_TO_POINTER (1));
+  g_object_set (contents,
+                "can-transfer-rich-text", priv->can_transfer_rich_text,
+                "rich-text-format",       priv->rich_text_format,
+                NULL);
+
+  g_object_set_data (G_OBJECT (contents), I_("gtk-text-buffer-clipboard"),
+                     GINT_TO_POINTER (1));
   
   return contents;
 }
@@ -2882,14 +3009,12 @@ clipboard_get_contents_cb (GtkClipboard 
                            guint             info,
                            gpointer          data)
 {
-  GtkTextBuffer *contents;
-
-  contents = GTK_TEXT_BUFFER (data);
+  GtkTextBuffer *contents = GTK_TEXT_BUFFER (data);
+  GtkTextBufferPrivate *priv = GTK_TEXT_BUFFER_GET_PRIVATE (contents);
   
   g_assert (contents); /* This should never be called unless we own the clipboard */
 
-  if (selection_data->target ==
-      gdk_atom_intern_static_string ("GTK_TEXT_BUFFER_CONTENTS"))
+  if (info == TARGET_BUFFER_CONTENTS)
     {
       /* Provide the address of the clipboard buffer; this will only
        * be used within-process. OK to supply a NULL value for contents.
@@ -2900,6 +3025,22 @@ clipboard_get_contents_cb (GtkClipboard 
                               (void*)&contents,
                               sizeof (contents));
     }
+  else if (info == TARGET_RICH_TEXT)
+    {
+      gchar *str;
+      gint *len;
+      GtkTextIter start, end;
+
+      gtk_text_buffer_get_bounds (contents, &start, &end);
+
+      str = _gtk_text_buffer_serialize_rich_text (contents, &start, &end, &len);
+
+      gtk_selection_data_set (selection_data,
+			      priv->rich_text_atom,
+			      8, /* bytes */
+			      str, len);
+      g_free (str);
+    }
   else
     {
       gchar *str;
@@ -3100,6 +3241,60 @@ restore_iter (const GtkTextIter *iter,
 #endif
 
 static void
+clipboard_text_view_rich_text_received (GtkClipboard     *clipboard,
+                                        GtkSelectionData *selection_data,
+                                        gpointer          data)
+{
+  ClipboardRequest *request_data = data;
+  GtkTextIter insert_point;
+  gboolean retval = TRUE;
+  GError *error = NULL;
+  GtkTextBufferPrivate *priv;
+
+  priv = GTK_TEXT_BUFFER_GET_PRIVATE (request_data->buffer);
+
+  /* The length is negative if the request failed. */
+  if (selection_data->length > 0 &&
+      selection_data->target == priv->rich_text_atom)
+    {
+      pre_paste_prep (request_data, &insert_point);
+
+      if (request_data->interactive)
+        gtk_text_buffer_begin_user_action (request_data->buffer);
+
+      if (!request_data->interactive ||
+          gtk_text_iter_can_insert (&insert_point,
+                                    request_data->default_editable))
+        retval = _gtk_text_buffer_deserialize_rich_text (request_data->buffer,
+                                                         &insert_point,
+                                                         (gchar *) selection_data->data,
+                                                         selection_data->length,
+                                                         priv->rich_text_format == NULL,
+                                                         &error);
+
+      if (!retval)
+        {
+          g_warning ("error pasting: %s\n", error->message);
+          g_clear_error (&error);
+        }
+
+      if (request_data->interactive)
+        gtk_text_buffer_end_user_action (request_data->buffer);
+
+      if (retval)
+        {
+          post_paste_cleanup (request_data);
+          return;
+        }
+    }
+
+  /* Request the text selection instead */
+  gtk_clipboard_request_text (clipboard,
+                              clipboard_text_received,
+                              data);
+}
+
+static void
 paste_from_buffer (ClipboardRequest    *request_data,
                    GtkTextBuffer       *src_buffer,
                    const GtkTextIter   *start,
@@ -3145,6 +3340,7 @@ clipboard_clipboard_buffer_received (Gtk
 {
   ClipboardRequest *request_data = data;
   GtkTextBuffer *src_buffer;
+  GtkTextBufferPrivate *priv;
   
   src_buffer = selection_data_get_buffer (selection_data, request_data); 
 
@@ -3168,21 +3364,28 @@ clipboard_clipboard_buffer_received (Gtk
     }
   else
     {
+      priv = GTK_TEXT_BUFFER_GET_PRIVATE (request_data->buffer);
+
+      if (priv->can_transfer_rich_text &&
+          gtk_clipboard_wait_is_target_available (clipboard,
+                                                  priv->rich_text_atom))
+        {
+          /* Request rich text */
+          gtk_clipboard_request_contents (clipboard,
+                                          priv->rich_text_atom,
+                                          clipboard_text_view_rich_text_received,
+                                          data);
+        }
+      else
+        {
       /* Request the text selection instead */
       gtk_clipboard_request_text (clipboard,
                                   clipboard_text_received,
                                   data);
     }
+    }
 }
 
-static const GtkTargetEntry targets[] = {
-  { "STRING", 0, TARGET_STRING },
-  { "TEXT",   0, TARGET_TEXT },
-  { "COMPOUND_TEXT", 0, TARGET_COMPOUND_TEXT },
-  { "UTF8_STRING", 0, TARGET_UTF8_STRING },
-  { "GTK_TEXT_BUFFER_CONTENTS", 0, TARGET_TEXT_BUFFER_CONTENTS }
-};
-
 typedef struct
 {
   GtkClipboard *clipboard;
@@ -3192,7 +3395,14 @@ typedef struct
 static void
 update_selection_clipboards (GtkTextBuffer *buffer)
 {
+  GtkTextBufferPrivate *priv;
   GSList *tmp_list = buffer->selection_clipboards;
+
+  priv = GTK_TEXT_BUFFER_GET_PRIVATE (buffer);
+
+  if (! priv->target_entries)
+    gtk_text_buffer_get_target_list (buffer);
+
   while (tmp_list)
     {
       GtkTextIter start;
@@ -3214,7 +3424,9 @@ update_selection_clipboards (GtkTextBuff
 	  /* Even if we already have the selection, we need to update our
 	   * timestamp.
 	   */
-	  if (!gtk_clipboard_set_with_owner (clipboard, targets, G_N_ELEMENTS (targets),
+	  if (!gtk_clipboard_set_with_owner (clipboard,
+                                             priv->target_entries,
+                                             priv->n_target_entries,
 					     clipboard_get_selection_cb,
 					     clipboard_clear_selection_cb,
 					     G_OBJECT (buffer)))
@@ -3525,6 +3737,8 @@ cut_or_copy (GtkTextBuffer *buffer,
              gboolean       interactive,
              gboolean       default_editable)
 {
+  GtkTextBufferPrivate *priv;
+
   /* We prefer to cut the selected region between selection_bound and
    * insertion point. If that region is empty, then we cut the region
    * between the "anchor" and the insertion point (this is for
@@ -3535,6 +3749,11 @@ cut_or_copy (GtkTextBuffer *buffer,
   GtkTextIter start;
   GtkTextIter end;
   
+  priv = GTK_TEXT_BUFFER_GET_PRIVATE (buffer);
+
+  if (! priv->target_entries)
+    gtk_text_buffer_get_target_list (buffer);
+
   if (!gtk_text_buffer_get_selection_bounds (buffer, &start, &end))
     {
       /* Let's try the anchor thing */
@@ -3560,13 +3779,17 @@ cut_or_copy (GtkTextBuffer *buffer,
       
       gtk_text_buffer_insert_range (contents, &ins, &start, &end);
                                     
-      if (!gtk_clipboard_set_with_data (clipboard, targets, G_N_ELEMENTS (targets),
+      if (!gtk_clipboard_set_with_data (clipboard,
+                                        priv->target_entries,
+                                        priv->n_target_entries,
 					clipboard_get_contents_cb,
 					clipboard_clear_contents_cb,
 					contents))
 	g_object_unref (contents);
       else
-	gtk_clipboard_set_can_store (clipboard, (GtkTargetEntry *)targets, G_N_ELEMENTS (targets) -1);
+	gtk_clipboard_set_can_store (clipboard,
+                                     priv->target_entries,
+                                     priv->n_target_entries - 1);
 				     
       if (delete_region_after)
         {
@@ -3697,6 +3920,226 @@ gtk_text_buffer_end_user_action (GtkText
       /* Ended the outermost-nested user action end, so emit the signal */
       g_signal_emit (buffer, signals[END_USER_ACTION], 0);
     }
+}
+
+static void
+gtk_text_buffer_free_target_list (GtkTextBuffer *buffer)
+{
+  GtkTextBufferPrivate *priv;
+  gint                  i;
+
+  g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
+
+  priv = GTK_TEXT_BUFFER_GET_PRIVATE (buffer);
+
+  if (priv->target_list)
+    {
+      gtk_target_list_unref (priv->target_list);
+      priv->target_list = NULL;
+
+      for (i = 0; i < priv->n_target_entries; i++)
+        g_free (priv->target_entries[i].target);
+
+      g_free (priv->target_entries);
+      priv->target_entries = NULL;
+      priv->n_target_entries = 0;
+    }
+}
+
+GtkTargetList *
+gtk_text_buffer_get_target_list (GtkTextBuffer *buffer)
+{
+  GtkTextBufferPrivate *priv;
+
+  g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
+
+  priv = GTK_TEXT_BUFFER_GET_PRIVATE (buffer);
+
+  if (! priv->target_list)
+    {
+      GList *list;
+      gint   i;
+
+      priv->target_list = gtk_target_list_new (NULL, 0);
+
+      gtk_target_list_add (priv->target_list,
+                           gdk_atom_intern_static_string ("GTK_TEXT_BUFFER_CONTENTS"),
+                           GTK_TARGET_SAME_APP,
+                           TARGET_BUFFER_CONTENTS);
+
+      if (priv->can_transfer_rich_text)
+        gtk_target_list_add (priv->target_list,
+                             priv->rich_text_atom,
+                             0,
+                             TARGET_RICH_TEXT);
+
+      gtk_target_list_add_text_targets (priv->target_list, TARGET_TEXT);
+
+      priv->n_target_entries = g_list_length (priv->target_list->list);
+      priv->target_entries = g_new0 (GtkTargetEntry, priv->n_target_entries);
+
+      for (i = 0, list = g_list_last (priv->target_list->list);
+           i < priv->n_target_entries;
+           i++, list = g_list_previous (list))
+        {
+          GtkTargetPair  *pair  = list->data;
+          GtkTargetEntry *entry = priv->target_entries + i;
+
+          entry->target = g_strdup (gdk_atom_name (pair->target));
+          entry->flags  = pair->flags;
+          entry->info   = pair->info;
+        }
+    }
+
+  return priv->target_list;
+}
+
+/**
+ * gtk_text_buffer_set_can_transfer_rich_text:
+ * @buffer: a #GtkTextBuffer
+ * @can_transfer_rich_text: whether rich text pasting and dropping is enabled
+ *
+ * Sets whether rich text can be pasted and dropped to the text buffer
+ *
+ * Since: 2.10
+ **/
+void
+gtk_text_buffer_set_can_transfer_rich_text (GtkTextBuffer *buffer,
+                                            gboolean       can_transfer_rich_text)
+{
+  GtkTextBufferPrivate *priv;
+
+  g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
+
+  priv = GTK_TEXT_BUFFER_GET_PRIVATE (buffer);
+
+  can_transfer_rich_text = (can_transfer_rich_text != FALSE);
+
+  if (priv->can_transfer_rich_text != can_transfer_rich_text)
+    {
+      priv->can_transfer_rich_text = can_transfer_rich_text;
+
+      if (priv->target_list)
+        gtk_text_buffer_free_target_list (buffer);
+
+      g_object_freeze_notify (G_OBJECT (buffer));
+      g_object_notify (G_OBJECT (buffer), "target-list");
+      g_object_notify (G_OBJECT (buffer), "can-transfer-rich-text");
+      g_object_thaw_notify (G_OBJECT (buffer));
+    }
+}
+
+/**
+ * gtk_text_buffer_get_can_transfer_rich_text:
+ * @buffer: a #GtkTextBuffer
+ *
+ * See gtk_text_buffer_set_can_transfer_rich_text().
+ *
+ * Return value: whether rich text pasting and dropping is enabled
+ *
+ * Since: 2.10
+ **/
+gboolean
+gtk_text_buffer_get_can_transfer_rich_text (GtkTextBuffer *buffer)
+{
+  GtkTextBufferPrivate *priv;
+
+  g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), FALSE);
+
+  priv = GTK_TEXT_BUFFER_GET_PRIVATE (buffer);
+
+  return priv->can_transfer_rich_text;
+}
+
+/**
+ * gtk_text_buffer_set_rich_text_format:
+ * @buffer: a #GtkTextBuffer
+ * @format: the rich text format
+ *
+ * The rich-text-format is a user-defined name of a collection of
+ * tags. Two text buffers can only exchange rich text if they share a
+ * common format, or have no format at all.
+ *
+ * Since: 2.10
+ **/
+void
+gtk_text_buffer_set_rich_text_format (GtkTextBuffer *buffer,
+                                      const gchar   *format)
+{
+  GtkTextBufferPrivate *priv;
+
+  g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
+
+  priv = GTK_TEXT_BUFFER_GET_PRIVATE (buffer);
+
+  g_free (priv->rich_text_format);
+  priv->rich_text_format = g_strdup (format);
+
+  if (priv->target_list)
+    gtk_text_buffer_free_target_list (buffer);
+
+  if (priv->rich_text_format)
+    {
+      gchar *tmp = g_strdup_printf ("application/x-gtk-text-view-rich-text;%s",
+                                    priv->rich_text_format);
+      priv->rich_text_atom = gdk_atom_intern (tmp, FALSE);
+      g_free (tmp);
+    }
+  else
+    {
+      priv->rich_text_atom = gdk_atom_intern_static_string ("application/x-gtk-text-view-rich-text");
+    }
+
+  g_object_freeze_notify (G_OBJECT (buffer));
+  g_object_notify (G_OBJECT (buffer), "target-list");
+  g_object_notify (G_OBJECT (buffer), "rich-text-format");
+  g_object_thaw_notify (G_OBJECT (buffer));
+}
+
+/**
+ * gtk_text_buffer_get_rich_text_format:
+ * @buffer: a #GtkTextBuffer
+ *
+ * Retrieve the rich text format from the text buffer. See
+ * gtk_text_buffer_set_rich_text_format().
+ *
+ * Return value: the rich text format.
+ *
+ * Since: 2.10
+ **/
+G_CONST_RETURN gchar *
+gtk_text_buffer_get_rich_text_format (GtkTextBuffer *buffer)
+{
+  GtkTextBufferPrivate *priv;
+
+  g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
+
+  priv = GTK_TEXT_BUFFER_GET_PRIVATE (buffer);
+
+  return priv->rich_text_format;
+}
+
+/**
+ * gtk_text_buffer_get_rich_text_atom:
+ * @buffer: a #GtkTextBuffer
+ *
+ * Retrieve the rich text atom from the text buffer. This value is needed
+ * to implement DND of rich text between different #GtkTextView widgets.
+ *
+ * Return value: the rich text atom.
+ *
+ * Since: 2.10
+ **/
+GdkAtom
+gtk_text_buffer_get_rich_text_atom (GtkTextBuffer *buffer)
+{
+  GtkTextBufferPrivate *priv;
+
+  g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
+
+  priv = GTK_TEXT_BUFFER_GET_PRIVATE (buffer);
+
+  return priv->rich_text_atom;
 }
 
 /*
Index: gtk/gtktextbuffer.h
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtktextbuffer.h,v
retrieving revision 1.38
diff -u -p -b -r1.38 gtktextbuffer.h
--- gtk/gtktextbuffer.h	7 Oct 2005 03:38:56 -0000	1.38
+++ gtk/gtktextbuffer.h	19 Jan 2006 15:08:57 -0000
@@ -367,6 +367,18 @@ gboolean        gtk_text_buffer_delete_s
 void            gtk_text_buffer_begin_user_action       (GtkTextBuffer *buffer);
 void            gtk_text_buffer_end_user_action         (GtkTextBuffer *buffer);
 
+GtkTargetList * gtk_text_buffer_get_target_list         (GtkTextBuffer *buffer);
+
+void         gtk_text_buffer_set_can_transfer_rich_text (GtkTextBuffer *buffer,
+							 gboolean       can_transfer_rich_text);
+gboolean     gtk_text_buffer_get_can_transfer_rich_text (GtkTextBuffer *buffer);
+
+void                  gtk_text_buffer_set_rich_text_format (GtkTextBuffer *buffer,
+							    const gchar   *format);
+G_CONST_RETURN gchar *gtk_text_buffer_get_rich_text_format (GtkTextBuffer *buffer);
+
+GdkAtom               gtk_text_buffer_get_rich_text_atom   (GtkTextBuffer *buffer);
+
 /* INTERNAL private stuff */
 void            _gtk_text_buffer_spew                  (GtkTextBuffer      *buffer);
 
Index: gtk/gtktextview.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtktextview.c,v
retrieving revision 1.303
diff -u -p -b -r1.303 gtktextview.c
--- gtk/gtktextview.c	12 Jan 2006 21:14:30 -0000	1.303
+++ gtk/gtktextview.c	19 Jan 2006 15:08:58 -0000
@@ -39,6 +39,7 @@
 #include "gtkseparatormenuitem.h"
 #include "gtksettings.h"
 #include "gtkstock.h"
+#include "gtktextbufferserialize.h"
 #include "gtktextdisplay.h"
 #include "gtktextview.h"
 #include "gtkimmulticontext.h"
@@ -314,6 +315,9 @@ static void gtk_text_view_mark_set_handl
                                                   const GtkTextIter *location,
                                                   GtkTextMark       *mark,
                                                   gpointer           data);
+static void gtk_text_view_target_list_notify     (GtkTextBuffer     *buffer,
+                                                  const GParamSpec  *pspec,
+                                                  gpointer           data);
 static void gtk_text_view_get_cursor_location    (GtkTextView       *text_view,
 						  GdkRectangle      *pos);
 static void gtk_text_view_get_virtual_cursor_pos (GtkTextView       *text_view,
@@ -414,10 +418,6 @@ static gint           text_window_get_wi
 static gint           text_window_get_height      (GtkTextWindow     *win);
 
 
-static const GtkTargetEntry target_table[] = {
-  { "GTK_TEXT_BUFFER_CONTENTS", GTK_TARGET_SAME_APP, 0 },
-};
-
 static GtkContainerClass *parent_class = NULL;
 static guint signals[LAST_SIGNAL] = { 0 };
 
@@ -1062,11 +1062,8 @@ gtk_text_view_init (GtkTextView *text_vi
   text_view->tabs = NULL;
   text_view->editable = TRUE;
 
-  gtk_drag_dest_set (widget,
-		     0,
-                     target_table, G_N_ELEMENTS (target_table),
+  gtk_drag_dest_set (widget, 0, NULL, 0,
                      GDK_ACTION_COPY | GDK_ACTION_MOVE);
-  gtk_drag_dest_add_text_targets (widget);
 
   text_view->virtual_cursor_x = -1;
   text_view->virtual_cursor_y = -1;
@@ -1190,6 +1187,9 @@ gtk_text_view_set_buffer (GtkTextView   
       g_signal_handlers_disconnect_by_func (text_view->buffer,
 					    gtk_text_view_mark_set_handler,
 					    text_view);
+      g_signal_handlers_disconnect_by_func (text_view->buffer,
+                                            gtk_text_view_target_list_notify,
+                                            text_view);
       g_object_unref (text_view->buffer);
       text_view->dnd_mark = NULL;
 
@@ -1225,7 +1225,13 @@ gtk_text_view_set_buffer (GtkTextView   
       text_view->first_para_pixels = 0;
 
       g_signal_connect (text_view->buffer, "mark_set",
-			G_CALLBACK (gtk_text_view_mark_set_handler), text_view);
+			G_CALLBACK (gtk_text_view_mark_set_handler),
+                        text_view);
+      g_signal_connect (text_view->buffer, "notify::target-list",
+			G_CALLBACK (gtk_text_view_target_list_notify),
+                        text_view);
+
+      gtk_text_view_target_list_notify (text_view->buffer, NULL, text_view);
 
       if (GTK_WIDGET_REALIZED (text_view))
 	{
@@ -6044,17 +6050,13 @@ gtk_text_view_start_selection_dnd (GtkTe
   text_view->drag_start_y = -1;
   text_view->pending_place_cursor_button = 0;
   
-  target_list = gtk_target_list_new (target_table,
-                                     G_N_ELEMENTS (target_table));
-  gtk_target_list_add_text_targets (target_list, 0);
+  target_list = gtk_text_buffer_get_target_list (get_buffer (text_view));
 
   g_signal_connect (text_view, "drag-begin", 
                     G_CALLBACK (drag_begin_cb), NULL);
   gtk_drag_begin (GTK_WIDGET (text_view), target_list,
 		  GDK_ACTION_COPY | GDK_ACTION_MOVE,
 		  1, (GdkEvent*)event);
-
-  gtk_target_list_unref (target_list);
 }
 
 static void
@@ -6077,30 +6079,49 @@ gtk_text_view_drag_data_get (GtkWidget  
                              guint             info,
                              guint             time)
 {
-  GtkTextView *text_view;
-
-  text_view = GTK_TEXT_VIEW (widget);
-
-  if (selection_data->target == gdk_atom_intern_static_string ("GTK_TEXT_BUFFER_CONTENTS"))
-    {
+  GtkTextView *text_view = GTK_TEXT_VIEW (widget);
       GtkTextBuffer *buffer = gtk_text_view_get_buffer (text_view);
 
+  if (selection_data->target ==
+      gdk_atom_intern_static_string ("GTK_TEXT_BUFFER_CONTENTS"))
+    {
       gtk_selection_data_set (selection_data,
                               gdk_atom_intern_static_string ("GTK_TEXT_BUFFER_CONTENTS"),
                               8, /* bytes */
                               (void*)&buffer,
                               sizeof (buffer));
     }
-  else
+  else if (selection_data->target ==
+           gtk_text_buffer_get_rich_text_atom (buffer))
     {
-      gchar *str;
       GtkTextIter start;
       GtkTextIter end;
+      gchar *str = NULL;
+      gint len;
 
-      str = NULL;
+      if (gtk_text_buffer_get_selection_bounds (buffer, &start, &end))
+        {
+          /* Extract the selected text */
+          str = _gtk_text_buffer_serialize_rich_text (buffer, &start, &end,
+                                                      &len);
+        }
 
-      if (gtk_text_buffer_get_selection_bounds (get_buffer (text_view),
-                                                &start, &end))
+      if (str)
+        {
+          gtk_selection_data_set (selection_data,
+                                  gtk_text_buffer_get_rich_text_atom (buffer),
+                                  8, /* bytes */
+                                  (guchar *) str, len);
+          g_free (str);
+        }
+    }
+  else
+    {
+      GtkTextIter start;
+      GtkTextIter end;
+      gchar *str = NULL;
+
+      if (gtk_text_buffer_get_selection_bounds (buffer, &start, &end))
         {
           /* Extract the selected text */
           str = gtk_text_iter_get_visible_text (&start, &end);
@@ -6329,7 +6350,8 @@ gtk_text_view_drag_data_received (GtkWid
 
   gtk_text_buffer_begin_user_action (buffer);
 
-  if (selection_data->target == gdk_atom_intern_static_string ("GTK_TEXT_BUFFER_CONTENTS"))
+  if (selection_data->target ==
+      gdk_atom_intern_static_string ("GTK_TEXT_BUFFER_CONTENTS"))
     {
       GtkTextBuffer *src_buffer = NULL;
       GtkTextIter start, end;
@@ -6371,6 +6393,26 @@ gtk_text_view_drag_data_received (GtkWid
             }
         }
     }
+  else if (selection_data->length > 0 &&
+           selection_data->target ==
+           gtk_text_buffer_get_rich_text_atom (buffer))
+    {
+      gboolean retval;
+      GError *error = NULL;
+
+      retval = _gtk_text_buffer_deserialize_rich_text (buffer,
+                                                       &drop_point,
+                                                       (gchar *) selection_data->data,
+                                                       selection_data->length,
+                                                       gtk_text_buffer_get_rich_text_format (buffer) == NULL,
+                                                       &error);
+
+      if (!retval)
+        {
+          g_warning ("error pasting: %s\n", error->message);
+          g_clear_error (&error);
+        }
+    }
   else
     insert_text_data (text_view, &drop_point, selection_data);
  
@@ -6823,6 +6865,14 @@ gtk_text_view_mark_set_handler (GtkTextB
 
   if (need_reset)
     gtk_text_view_reset_im_context (text_view);
+}
+
+static void
+gtk_text_view_target_list_notify (GtkTextBuffer    *buffer,
+                                  const GParamSpec *pspec,
+                                  gpointer          data)
+{
+  gtk_drag_dest_set_target_list (data, gtk_text_buffer_get_target_list (buffer));
 }
 
 static void
Index: gtk/gtkselection.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkselection.c,v
retrieving revision 1.107
diff -u -p -b -r1.107 gtkselection.c
--- gtk/gtkselection.c	20 Dec 2005 05:36:10 -0000	1.107
+++ gtk/gtkselection.c	19 Jan 2006 15:08:59 -0000
@@ -214,12 +214,14 @@ gtk_target_list_new (const GtkTargetEntr
  * Increases the reference count of a #GtkTargetList by one.
  *
  **/
-void               
+GtkTargetList *
 gtk_target_list_ref (GtkTargetList *list)
 {
-  g_return_if_fail (list != NULL);
+  g_return_val_if_fail (list != NULL, NULL);
 
   list->ref_count++;
+
+  return list;
 }
 
 /**
@@ -2752,6 +2754,19 @@ gtk_selection_data_get_type (void)
     our_type = g_boxed_type_register_static (I_("GtkSelectionData"),
 					     (GBoxedCopyFunc) gtk_selection_data_copy,
 					     (GBoxedFreeFunc) gtk_selection_data_free);
+
+  return our_type;
+}
+
+GType
+gtk_target_list_get_type (void)
+{
+  static GType our_type = 0;
+
+  if (our_type == 0)
+    our_type = g_boxed_type_register_static (I_("GtkTargetList"),
+					     (GBoxedCopyFunc) gtk_target_list_ref,
+					     (GBoxedFreeFunc) gtk_target_list_unref);
 
   return our_type;
 }
Index: gtk/gtkselection.h
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkselection.h,v
retrieving revision 1.30
diff -u -p -b -r1.30 gtkselection.h
--- gtk/gtkselection.h	30 Aug 2005 05:42:36 -0000	1.30
+++ gtk/gtkselection.h	19 Jan 2006 15:08:59 -0000
@@ -38,6 +38,7 @@ typedef struct _GtkTargetList    GtkTarg
 typedef struct _GtkTargetEntry   GtkTargetEntry;
 
 #define GTK_TYPE_SELECTION_DATA (gtk_selection_data_get_type ())
+#define GTK_TYPE_TARGET_LIST    (gtk_target_list_get_type ())
 
 /* The contents of a selection are returned in a GtkSelectionData
  * structure. selection/target identify the request.  type specifies
@@ -87,7 +88,7 @@ struct _GtkTargetPair {
 
 GtkTargetList *gtk_target_list_new       (const GtkTargetEntry *targets,
 					  guint                 ntargets);
-void           gtk_target_list_ref       (GtkTargetList  *list);
+GtkTargetList *gtk_target_list_ref       (GtkTargetList  *list);
 void           gtk_target_list_unref     (GtkTargetList  *list);
 void           gtk_target_list_add       (GtkTargetList  *list,
 				  	  GdkAtom         target,
@@ -186,6 +187,7 @@ GType             gtk_selection_data_get
 GtkSelectionData *gtk_selection_data_copy     (GtkSelectionData *data);
 void		  gtk_selection_data_free     (GtkSelectionData *data);
 
+GType             gtk_target_list_get_type    (void) G_GNUC_CONST;
 
 G_END_DECLS
 
