Index: gtk/Makefile.am
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/Makefile.am,v
retrieving revision 1.293
diff -u -p -r1.293 Makefile.am
--- gtk/Makefile.am	5 Feb 2006 04:04:29 -0000	1.293
+++ gtk/Makefile.am	7 Mar 2006 13:21:31 -0000
@@ -248,6 +248,7 @@ gtk_public_h_sources =          \
 	gtktearoffmenuitem.h    \
 	gtktext.h		\
 	gtktextbuffer.h		\
+	gtktextbufferrichtext.h	\
 	gtktextchild.h		\
 	gtktextdisplay.h	\
 	gtktextiter.h		\
@@ -481,6 +482,9 @@ gtk_c_sources =                 \
 	gtktext.c		\
 	gtktextbtree.c		\
 	gtktextbuffer.c		\
+	gtktextbufferrichtext.c	\
+	gtktextbufferserialize.c\
+	gtktextbufferserialize.h\
 	gtktextchild.c		\
 	gtktextdisplay.c	\
 	gtktextiter.c		\
Index: gtk/gtk.h
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtk.h,v
retrieving revision 1.80
diff -u -p -r1.80 gtk.h
--- gtk/gtk.h	24 Jan 2006 03:35:51 -0000	1.80
+++ gtk/gtk.h	7 Mar 2006 13:21:32 -0000
@@ -160,6 +160,7 @@
 #include <gtk/gtktearoffmenuitem.h>
 #include <gtk/gtktext.h>
 #include <gtk/gtktextbuffer.h>
+#include <gtk/gtktextbufferrichtext.h>
 #include <gtk/gtktextview.h>
 #include <gtk/gtktipsquery.h>
 #include <gtk/gtktoggleaction.h>
Index: gtk/gtk.symbols
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtk.symbols,v
retrieving revision 1.87
diff -u -p -r1.87 gtk.symbols
--- gtk/gtk.symbols	27 Feb 2006 16:48:34 -0000	1.87
+++ gtk/gtk.symbols	7 Mar 2006 13:21:32 -0000
@@ -600,6 +600,7 @@ gtk_clipboard_get_owner
 gtk_clipboard_get_type G_GNUC_CONST
 gtk_clipboard_request_contents
 gtk_clipboard_request_image
+gtk_clipboard_request_rich_text
 gtk_clipboard_request_targets
 gtk_clipboard_request_text
 gtk_clipboard_set_can_store
@@ -610,9 +611,11 @@ gtk_clipboard_set_with_owner
 gtk_clipboard_store
 gtk_clipboard_wait_for_contents
 gtk_clipboard_wait_for_image
+gtk_clipboard_wait_for_rich_text
 gtk_clipboard_wait_for_targets
 gtk_clipboard_wait_for_text
 gtk_clipboard_wait_is_image_available
+gtk_clipboard_wait_is_rich_text_available
 gtk_clipboard_wait_is_text_available
 gtk_clipboard_wait_is_target_available
 #endif
@@ -2607,6 +2610,23 @@ gtk_rc_style_unref
 #endif
 #endif
 
+#if IN_HEADER(__GTK_TEXT_BUFFER_RICH_TEXT_H__)
+#if IN_FILE(__GTK_TEXT_BUFFER_RICH_TEXT_C__)
+gtk_text_buffer_deserialize
+gtk_text_buffer_deserialize_get_can_create_tags
+gtk_text_buffer_deserialize_set_can_create_tags
+gtk_text_buffer_get_deserialize_formats
+gtk_text_buffer_get_serialize_formats
+gtk_text_buffer_register_deserialize_format
+gtk_text_buffer_register_deserialize_tagset
+gtk_text_buffer_register_serialize_format
+gtk_text_buffer_register_serialize_tagset
+gtk_text_buffer_serialize
+gtk_text_buffer_unregister_deserialize_format
+gtk_text_buffer_unregister_serialize_format
+#endif
+#endif
+
 #if IN_HEADER(__GTK_RULER_H__)
 #if IN_FILE(__GTK_RULER_C__)
 gtk_ruler_draw_pos
@@ -2678,9 +2698,11 @@ gtk_selection_data_set_pixbuf
 gtk_selection_data_set_text
 gtk_selection_data_set_uris
 gtk_selection_data_targets_include_image
+gtk_selection_data_targets_include_rich_text
 gtk_selection_data_targets_include_text
 gtk_selection_data_targets_include_uri
 gtk_targets_include_image
+gtk_targets_include_rich_text
 gtk_targets_include_text
 gtk_targets_include_uri
 gtk_selection_owner_set
@@ -2688,14 +2710,18 @@ gtk_selection_owner_set_for_display
 gtk_selection_remove_all
 gtk_target_list_add
 gtk_target_list_add_image_targets
+gtk_target_list_add_rich_text_targets
 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 G_GNUC_CONST
 gtk_target_list_new
 gtk_target_list_ref
 gtk_target_list_remove
 gtk_target_list_unref
+gtk_target_table_new_from_list
+gtk_target_table_free
 #endif
 #endif
 
@@ -2934,6 +2960,7 @@ gtk_text_buffer_delete_selection
 gtk_text_buffer_end_user_action
 gtk_text_buffer_get_bounds
 gtk_text_buffer_get_char_count
+gtk_text_buffer_get_copy_target_list
 gtk_text_buffer_get_end_iter
 gtk_text_buffer_get_has_selection
 gtk_text_buffer_get_insert
@@ -2946,6 +2973,7 @@ 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_paste_target_list
 gtk_text_buffer_get_selection_bound
 gtk_text_buffer_get_selection_bounds
 gtk_text_buffer_get_slice
Index: gtk/gtkclipboard.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkclipboard.c,v
retrieving revision 1.46
diff -u -p -r1.46 gtkclipboard.c
--- gtk/gtkclipboard.c	10 Nov 2005 12:09:41 -0000	1.46
+++ gtk/gtkclipboard.c	7 Mar 2006 13:21:33 -0000
@@ -27,6 +27,7 @@
 #include "gtkinvisible.h"
 #include "gtkmain.h"
 #include "gtkmarshalers.h"
+#include "gtktextbufferrichtext.h"
 #include "gtkintl.h"
 #include "gtkalias.h"
 
@@ -47,6 +48,7 @@ typedef struct _GtkClipboardClass GtkCli
 
 typedef struct _RequestContentsInfo RequestContentsInfo;
 typedef struct _RequestTextInfo RequestTextInfo;
+typedef struct _RequestRichTextInfo RequestRichTextInfo;
 typedef struct _RequestImageInfo RequestImageInfo;
 typedef struct _RequestTargetsInfo RequestTargetsInfo;
 
@@ -97,6 +99,15 @@ struct _RequestTextInfo
   gpointer user_data;
 };
 
+struct _RequestRichTextInfo
+{
+  GtkClipboardRichTextReceivedFunc callback;
+  GdkAtom *atoms;
+  gint     n_atoms;
+  gint     current_atom;
+  gpointer user_data;
+};
+
 struct _RequestImageInfo
 {
   GtkClipboardImageReceivedFunc callback;
@@ -927,7 +938,7 @@ request_text_received_func (GtkClipboard
   RequestTextInfo *info = data;
   gchar *result = NULL;
 
-  result = gtk_selection_data_get_text (selection_data);
+  result = (gchar *) gtk_selection_data_get_text (selection_data);
 
   if (!result)
     {
@@ -992,6 +1003,80 @@ gtk_clipboard_request_text (GtkClipboard
 				  info);
 }
 
+static void
+request_rich_text_received_func (GtkClipboard     *clipboard,
+                                 GtkSelectionData *selection_data,
+                                 gpointer          data)
+{
+  RequestRichTextInfo *info = data;
+  guint8 *result = NULL;
+  gsize length = 0;
+
+  result = selection_data->data;
+  length = selection_data->length;
+
+  info->current_atom++;
+
+  if ((!result || length < 1) && (info->current_atom < info->n_atoms))
+    {
+      gtk_clipboard_request_contents (clipboard, info->atoms[info->current_atom],
+                                      request_rich_text_received_func,
+                                      info);
+      return;
+    }
+
+  info->callback (clipboard, selection_data->target, result, length,
+                  info->user_data);
+  g_free (info->atoms);
+  g_free (info);
+}
+
+/**
+ * gtk_clipboard_request_rich_text:
+ * @clipboard: a #GtkClipboard
+ * @buffer:    a #GtkTextBuffer
+ * @callback:  a function to call when the text is received,
+ *             or the retrieval fails. (It will always be called
+ *             one way or the other.)
+ * @user_data: user data to pass to @callback.
+ *
+ * Requests the contents of the clipboard as rich text. When the rich
+ * text is later received, @callback will be called.
+ *
+ * The @text parameter to @callback will contain the resulting rich
+ * text if the request succeeded, or %NULL if it failed. The @length
+ * parameter will contain @text's length. This function can fail for
+ * various reasons, in particular if the clipboard was empty or if the
+ * contents of the clipboard could not be converted into rich text form.
+ *
+ * Since: 2.10
+ **/
+void
+gtk_clipboard_request_rich_text (GtkClipboard                    *clipboard,
+                                 GtkTextBuffer                   *buffer,
+                                 GtkClipboardRichTextReceivedFunc callback,
+                                 gpointer                         user_data)
+{
+  RequestRichTextInfo *info;
+
+  g_return_if_fail (clipboard != NULL);
+  g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
+  g_return_if_fail (callback != NULL);
+
+  info = g_new (RequestRichTextInfo, 1);
+  info->callback = callback;
+  info->atoms = NULL;
+  info->n_atoms = 0;
+  info->current_atom = 0;
+  info->user_data = user_data;
+
+  info->atoms = gtk_text_buffer_get_deserialize_formats (buffer, &info->n_atoms);
+
+  gtk_clipboard_request_contents (clipboard, info->atoms[info->current_atom],
+				  request_rich_text_received_func,
+				  info);
+}
+
 static void 
 request_image_received_func (GtkClipboard     *clipboard,
 			     GtkSelectionData *selection_data,
@@ -1143,6 +1228,8 @@ typedef struct
 {
   GMainLoop *loop;
   gpointer data;
+  GdkAtom format; /* used by rich text */
+  gsize length; /* used by rich text */
 } WaitResults;
 
 static void 
@@ -1254,6 +1341,75 @@ gtk_clipboard_wait_for_text (GtkClipboar
   return results.data;
 }
 
+static void
+clipboard_rich_text_received_func (GtkClipboard *clipboard,
+                                   GdkAtom       format,
+                                   const guint8 *text,
+                                   gsize         length,
+                                   gpointer      data)
+{
+  WaitResults *results = data;
+
+  results->data = g_memdup (text, length);
+  results->format = format;
+  results->length = length;
+  g_main_loop_quit (results->loop);
+}
+
+/**
+ * gtk_clipboard_wait_for_rich_text:
+ * @clipboard: a #GtkClipboard
+ * @buffer: a #GtkTextBuffer
+ * @length: return location for the length of the returned data
+ *
+ * Requests the contents of the clipboard as rich text.  This function
+ * waits for the data to be received using the main loop, so events,
+ * timeouts, etc, may be dispatched during the wait.
+ *
+ * Return value: a newly-allocated binary block of data which must
+ *               be freed with g_free(), or %NULL if retrieving
+ *               the selection data failed. (This could happen
+ *               for various reasons, in particular if the
+ *               clipboard was empty or if the contents of the
+ *               clipboard could not be converted into text form.)
+ *
+ * Since: 2.10
+ **/
+guint8 *
+gtk_clipboard_wait_for_rich_text (GtkClipboard  *clipboard,
+                                  GtkTextBuffer *buffer,
+                                  GdkAtom       *format,
+                                  gsize         *length)
+{
+  WaitResults results;
+
+  g_return_val_if_fail (clipboard != NULL, NULL);
+  g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
+  g_return_val_if_fail (format != NULL, NULL);
+  g_return_val_if_fail (length != NULL, NULL);
+
+  results.data = NULL;
+  results.loop = g_main_loop_new (NULL, TRUE);
+
+  gtk_clipboard_request_rich_text (clipboard, buffer,
+                                   clipboard_rich_text_received_func,
+                                   &results);
+
+  if (g_main_loop_is_running (results.loop))
+    {
+      GDK_THREADS_LEAVE ();
+      g_main_loop_run (results.loop);
+      GDK_THREADS_ENTER ();
+    }
+
+  g_main_loop_unref (results.loop);
+
+  *format = results.format;
+  *length = results.length;
+
+  return results.data;
+}
+
 static void 
 clipboard_image_received_func (GtkClipboard *clipboard,
 			       GdkPixbuf    *pixbuf,
@@ -1355,6 +1511,45 @@ gtk_clipboard_wait_is_text_available (Gt
   if (data)
     {
       result = gtk_selection_data_targets_include_text (data);
+      gtk_selection_data_free (data);
+    }
+
+  return result;
+}
+
+/**
+ * gtk_clipboard_wait_is_rich_text_available:
+ * @clipboard: a #GtkClipboard
+ * @buffer: a #GtkTextBuffer
+ *
+ * Test to see if there is rich text available to be pasted
+ * This is done by requesting the TARGETS atom and checking
+ * if it contains any of the supported rich text targets. This function
+ * waits for the data to be received using the main loop, so events,
+ * timeouts, etc, may be dispatched during the wait.
+ *
+ * This function is a little faster than calling
+ * gtk_clipboard_wait_for_rich_text() since it doesn't need to retrieve
+ * the actual text.
+ *
+ * Return value: %TRUE is there is rich text available, %FALSE otherwise.
+ *
+ * Since: 2.10
+ **/
+gboolean
+gtk_clipboard_wait_is_rich_text_available (GtkClipboard  *clipboard,
+                                           GtkTextBuffer *buffer)
+{
+  GtkSelectionData *data;
+  gboolean result = FALSE;
+
+  g_return_val_if_fail (GTK_IS_CLIPBOARD (clipboard), FALSE);
+  g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), FALSE);
+
+  data = gtk_clipboard_wait_for_contents (clipboard, gdk_atom_intern_static_string ("TARGETS"));
+  if (data)
+    {
+      result = gtk_selection_data_targets_include_rich_text (data, buffer);
       gtk_selection_data_free (data);
     }
 
Index: gtk/gtkclipboard.h
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkclipboard.h,v
retrieving revision 1.13
diff -u -p -r1.13 gtkclipboard.h
--- gtk/gtkclipboard.h	20 Mar 2005 07:01:21 -0000	1.13
+++ gtk/gtkclipboard.h	7 Mar 2006 13:21:33 -0000
@@ -30,19 +30,24 @@ G_BEGIN_DECLS
 #define GTK_CLIPBOARD(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_CLIPBOARD, GtkClipboard))
 #define GTK_IS_CLIPBOARD(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_CLIPBOARD))
 
-typedef void (* GtkClipboardReceivedFunc)        (GtkClipboard     *clipboard,
-					          GtkSelectionData *selection_data,
-					          gpointer          data);
-typedef void (* GtkClipboardTextReceivedFunc)    (GtkClipboard     *clipboard,
-					          const gchar      *text,
-					          gpointer          data);
-typedef void (* GtkClipboardImageReceivedFunc)   (GtkClipboard     *clipboard,
-						  GdkPixbuf        *pixbuf,
-						  gpointer          data);
-typedef void (* GtkClipboardTargetsReceivedFunc) (GtkClipboard     *clipboard,
-					          GdkAtom          *atoms,
-						  gint              n_atoms,
-					          gpointer          data);
+typedef void (* GtkClipboardReceivedFunc)         (GtkClipboard     *clipboard,
+					           GtkSelectionData *selection_data,
+					           gpointer          data);
+typedef void (* GtkClipboardTextReceivedFunc)     (GtkClipboard     *clipboard,
+					           const gchar      *text,
+					           gpointer          data);
+typedef void (* GtkClipboardRichTextReceivedFunc) (GtkClipboard     *clipboard,
+                                                   GdkAtom           format,
+					           const guint8     *text,
+                                                   gsize             length,
+					           gpointer          data);
+typedef void (* GtkClipboardImageReceivedFunc)    (GtkClipboard     *clipboard,
+						   GdkPixbuf        *pixbuf,
+						   gpointer          data);
+typedef void (* GtkClipboardTargetsReceivedFunc)  (GtkClipboard     *clipboard,
+					           GdkAtom          *atoms,
+						   gint              n_atoms,
+					           gpointer          data);
 
 /* Should these functions have GtkClipboard *clipboard as the first argument?
  * right now for ClearFunc, you may have trouble determining _which_ clipboard
@@ -86,32 +91,42 @@ void     gtk_clipboard_set_text       (G
 void     gtk_clipboard_set_image      (GtkClipboard          *clipboard,
 				       GdkPixbuf             *pixbuf);
 
-void gtk_clipboard_request_contents (GtkClipboard                    *clipboard,
-				     GdkAtom                          target,
-				     GtkClipboardReceivedFunc         callback,
-				     gpointer                         user_data);
-void gtk_clipboard_request_text     (GtkClipboard                    *clipboard,
-				     GtkClipboardTextReceivedFunc     callback,
-				     gpointer                         user_data);
-void gtk_clipboard_request_image    (GtkClipboard                    *clipboard,
-				     GtkClipboardImageReceivedFunc    callback,
-				     gpointer                         user_data);
-void gtk_clipboard_request_targets  (GtkClipboard                    *clipboard,
-				     GtkClipboardTargetsReceivedFunc  callback,
-				     gpointer                         user_data);
-
-GtkSelectionData *gtk_clipboard_wait_for_contents (GtkClipboard  *clipboard,
-						   GdkAtom        target);
-gchar *           gtk_clipboard_wait_for_text     (GtkClipboard  *clipboard);
-GdkPixbuf *       gtk_clipboard_wait_for_image    (GtkClipboard  *clipboard);
-gboolean          gtk_clipboard_wait_for_targets  (GtkClipboard  *clipboard,
-						   GdkAtom      **targets,
-						   gint          *n_targets);
-
-gboolean gtk_clipboard_wait_is_text_available   (GtkClipboard *clipboard);
-gboolean gtk_clipboard_wait_is_image_available  (GtkClipboard *clipboard);
-gboolean gtk_clipboard_wait_is_target_available (GtkClipboard *clipboard,
-						 GdkAtom       target);
+void gtk_clipboard_request_contents  (GtkClipboard                     *clipboard,
+                                      GdkAtom                           target,
+                                      GtkClipboardReceivedFunc          callback,
+                                      gpointer                          user_data);
+void gtk_clipboard_request_text      (GtkClipboard                     *clipboard,
+                                      GtkClipboardTextReceivedFunc      callback,
+                                      gpointer                          user_data);
+void gtk_clipboard_request_rich_text (GtkClipboard                     *clipboard,
+                                      GtkTextBuffer                    *buffer,
+                                      GtkClipboardRichTextReceivedFunc  callback,
+                                      gpointer                          user_data);
+void gtk_clipboard_request_image     (GtkClipboard                     *clipboard,
+                                      GtkClipboardImageReceivedFunc     callback,
+                                      gpointer                          user_data);
+void gtk_clipboard_request_targets   (GtkClipboard                     *clipboard,
+                                      GtkClipboardTargetsReceivedFunc   callback,
+                                      gpointer                          user_data);
+
+GtkSelectionData *gtk_clipboard_wait_for_contents  (GtkClipboard  *clipboard,
+                                                    GdkAtom        target);
+gchar *           gtk_clipboard_wait_for_text      (GtkClipboard  *clipboard);
+guint8 *          gtk_clipboard_wait_for_rich_text (GtkClipboard  *clipboard,
+                                                    GtkTextBuffer *buffer,
+                                                    GdkAtom       *format,
+                                                    gsize         *size);
+GdkPixbuf *       gtk_clipboard_wait_for_image     (GtkClipboard  *clipboard);
+gboolean          gtk_clipboard_wait_for_targets   (GtkClipboard  *clipboard,
+                                                    GdkAtom      **targets,
+                                                    gint          *n_targets);
+
+gboolean gtk_clipboard_wait_is_text_available      (GtkClipboard  *clipboard);
+gboolean gtk_clipboard_wait_is_rich_text_available (GtkClipboard  *clipboard,
+                                                    GtkTextBuffer *buffer);
+gboolean gtk_clipboard_wait_is_image_available     (GtkClipboard  *clipboard);
+gboolean gtk_clipboard_wait_is_target_available    (GtkClipboard  *clipboard,
+                                                    GdkAtom        target);
 
 
 void gtk_clipboard_set_can_store (GtkClipboard         *clipboard,
Index: gtk/gtkselection.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkselection.c,v
retrieving revision 1.107
diff -u -p -r1.107 gtkselection.c
--- gtk/gtkselection.c	20 Dec 2005 05:36:10 -0000	1.107
+++ gtk/gtkselection.c	7 Mar 2006 13:21:34 -0000
@@ -58,6 +58,7 @@
 
 #include "gtkmain.h"
 #include "gtkselection.h"
+#include "gtktextbufferrichtext.h"
 #include "gtkintl.h"
 #include "gdk-pixbuf/gdk-pixbuf.h"
 
@@ -213,13 +214,16 @@ gtk_target_list_new (const GtkTargetEntr
  * 
  * Increases the reference count of a #GtkTargetList by one.
  *
+ * Return value: the passed in #GtkTargetList.
  **/
-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;
 }
 
 /**
@@ -339,6 +343,45 @@ gtk_target_list_add_text_targets (GtkTar
 }
 
 /**
+ * gtk_target_list_add_rich_text_targets:
+ * @list: a #GtkTargetList
+ * @info: an ID that will be passed back to the application
+ * @deserializable: if %TRUE, then deserializable rich text formats
+ *                  will be added, serializable formats otherwise.
+ * @buffer: a #GtkTextBuffer.
+ *
+ * Appends the rich text targets registered with
+ * gtk_text_buffer_register_serialize_format() or
+ * gtk_text_buffer_register_deserialize_format() to the target list. All
+ * targets are added with the same @info.
+ *
+ * Since: 2.10
+ **/
+void
+gtk_target_list_add_rich_text_targets (GtkTargetList  *list,
+                                       guint           info,
+                                       gboolean        deserializable,
+                                       GtkTextBuffer  *buffer)
+{
+  GdkAtom *atoms;
+  gint     n_atoms;
+  gint     i;
+
+  g_return_if_fail (list != NULL);
+  g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
+
+  if (deserializable)
+    atoms = gtk_text_buffer_get_deserialize_formats (buffer, &n_atoms);
+  else
+    atoms = gtk_text_buffer_get_serialize_formats (buffer, &n_atoms);
+
+  for (i = 0; i < n_atoms; i++)
+    gtk_target_list_add (list, atoms[i], 0, info);
+
+  g_free (atoms);
+}
+
+/**
  * gtk_target_list_add_image_targets:
  * @list: a #GtkTargetList
  * @info: an ID that will be passed back to the application
@@ -515,6 +558,72 @@ gtk_target_list_find (GtkTargetList *lis
 }
 
 /**
+ * gtk_target_table_new_from_list:
+ * @list: a #GtkTargetList
+ * @n_targets: return location for the number ot targets in the table
+ *
+ * This function creates an #GtkTargetEntry array that contains the
+ * same targets as the passed %list. The returned table is newly
+ * allocated and should be freed using gtk_target_table_free() when no
+ * longer needed.
+ *
+ * Return value: the new table.
+ *
+ * Since: 2.10
+ **/
+GtkTargetEntry *
+gtk_target_table_new_from_list (GtkTargetList *list,
+                                gint          *n_targets)
+{
+  GtkTargetEntry *targets;
+  GList          *tmp_list;
+  gint            i;
+
+  g_return_val_if_fail (list != NULL, NULL);
+  g_return_val_if_fail (n_targets != NULL, NULL);
+
+  *n_targets = g_list_length (list->list);
+  targets = g_new0 (GtkTargetEntry, *n_targets);
+
+  for (i = 0, tmp_list = list->list;
+       i < *n_targets;
+       i++, tmp_list = g_list_next (tmp_list))
+    {
+      GtkTargetPair *pair = tmp_list->data;
+
+      targets[i].target = gdk_atom_name (pair->target);
+      targets[i].flags  = pair->flags;
+      targets[i].info   = pair->info;
+    }
+
+  return targets;
+}
+
+/**
+ * gtk_target_table_free:
+ * @targets: a #GtkTargetEntry array
+ * @n_targets: the number of entries in the array
+ *
+ * This function frees a target table as returned by
+ * gtk_target_table_new_from_list()
+ *
+ * Since: 2.10
+ **/
+void
+gtk_target_table_free (GtkTargetEntry *targets,
+                       gint            n_targets)
+{
+  gint i;
+
+  g_return_if_fail (targets == NULL || n_targets > 0);
+
+  for (i = 0; i < n_targets; i++)
+    g_free (targets[i].target);
+
+  g_free (targets);
+}
+
+/**
  * gtk_selection_owner_set_for_display:
  * @display: the #Gdkdisplay where the selection is set 
  * @widget: new selection owner (a #GdkWidget), or %NULL.
@@ -1608,7 +1717,54 @@ gtk_targets_include_text (GdkAtom *targe
   
   return result;
 }
-				    
+
+/**
+ * gtk_targets_include_rich_text:
+ * @targets: an array of #GdkAtom<!-- -->s
+ * @n_targets: the length of @targets
+ * @buffer: a #GtkTextBuffer
+ *
+ * Determines if any of the targets in @targets can be used to
+ * provide rich text.
+ *
+ * Return value: %TRUE if @targets include a suitable target for rich text,
+ *               otherwise %FALSE.
+ *
+ * Since: 2.10
+ **/
+gboolean
+gtk_targets_include_rich_text (GdkAtom       *targets,
+                               gint           n_targets,
+                               GtkTextBuffer *buffer)
+{
+  GdkAtom *rich_targets;
+  gint n_rich_targets;
+  gint i, j;
+  gboolean result = FALSE;
+
+  g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), FALSE);
+
+  rich_targets = gtk_text_buffer_get_deserialize_formats (buffer,
+                                                          &n_rich_targets);
+
+  for (i = 0; i < n_targets; i++)
+    {
+      for (j = 0; j < n_rich_targets; j++)
+        {
+          if (targets[i] == rich_targets[j])
+            {
+              result = TRUE;
+              goto done;
+            }
+        }
+    }
+
+ done:
+  g_free (rich_targets);
+
+  return result;
+}
+
 /**
  * gtk_selection_data_targets_include_text:
  * @selection_data: a #GtkSelectionData object
@@ -1639,6 +1795,42 @@ gtk_selection_data_targets_include_text 
 }
 
 /**
+ * gtk_selection_data_targets_include_rich_text:
+ * @selection_data: a #GtkSelectionData object
+ * @buffer: a #GtkTextBuffer
+ *
+ * Given a #GtkSelectionData object holding a list of targets,
+ * determines if any of the targets in @targets can be used to
+ * provide rich text.
+ *
+ * Return value: %TRUE if @selection_data holds a list of targets,
+ *               and a suitable target for rich text is included,
+ *               otherwise %FALSE.
+ *
+ * Since: 2.10
+ **/
+gboolean
+gtk_selection_data_targets_include_rich_text (GtkSelectionData *selection_data,
+                                              GtkTextBuffer    *buffer)
+{
+  GdkAtom *targets;
+  gint n_targets;
+  gboolean result = FALSE;
+
+  g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), FALSE);
+
+  init_atoms ();
+
+  if (gtk_selection_data_get_targets (selection_data, &targets, &n_targets))
+    {
+      result = gtk_targets_include_rich_text (targets, n_targets, buffer);
+      g_free (targets);
+    }
+
+  return result;
+}
+
+/**
  * gtk_targets_include_image:
  * @targets: an array of #GdkAtom<!-- -->s
  * @n_targets: the length of @targets
@@ -2752,6 +2944,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 -r1.30 gtkselection.h
--- gtk/gtkselection.h	30 Aug 2005 05:42:36 -0000	1.30
+++ gtk/gtkselection.h	7 Mar 2006 13:21:34 -0000
@@ -31,6 +31,7 @@
 #include <gdk/gdk.h>
 #include <gtk/gtkenums.h>
 #include <gtk/gtkwidget.h>
+#include <gtk/gtktextiter.h>
 
 G_BEGIN_DECLS
 
@@ -38,6 +39,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,19 +89,23 @@ 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,
 					  guint           flags,
 					  guint           info);
-void           gtk_target_list_add_text_targets  (GtkTargetList  *list,
-						  guint           info);
-void           gtk_target_list_add_image_targets (GtkTargetList  *list,
-						  guint           info,
-						  gboolean        writable);
-void           gtk_target_list_add_uri_targets   (GtkTargetList  *list,
-						  guint           info);
+void           gtk_target_list_add_text_targets      (GtkTargetList  *list,
+                                                      guint           info);
+void           gtk_target_list_add_rich_text_targets (GtkTargetList  *list,
+                                                      guint           info,
+                                                      gboolean        deserializable,
+                                                      GtkTextBuffer  *buffer);
+void           gtk_target_list_add_image_targets     (GtkTargetList  *list,
+                                                      guint           info,
+                                                      gboolean        writable);
+void           gtk_target_list_add_uri_targets       (GtkTargetList  *list,
+                                                      guint           info);
 void           gtk_target_list_add_table (GtkTargetList        *list,
 					  const GtkTargetEntry *targets,
 					  guint                 ntargets);
@@ -109,6 +115,11 @@ gboolean       gtk_target_list_find     
 					  GdkAtom         target,
 					  guint          *info);
 
+GtkTargetEntry * gtk_target_table_new_from_list (GtkTargetList  *list,
+                                                 gint           *n_targets);
+void             gtk_target_table_free          (GtkTargetEntry *targets,
+                                                 gint            n_targets);
+
 /* Public interface */
 
 gboolean gtk_selection_owner_set             (GtkWidget  *widget,
@@ -153,16 +164,21 @@ gboolean gtk_selection_data_get_targets 
 						  GdkAtom          **targets,
 						  gint              *n_atoms);
 gboolean gtk_selection_data_targets_include_text (GtkSelectionData  *selection_data);
+gboolean gtk_selection_data_targets_include_rich_text (GtkSelectionData *selection_data,
+                                                       GtkTextBuffer    *buffer);
 gboolean gtk_selection_data_targets_include_image (GtkSelectionData  *selection_data,
 						   gboolean           writable);
 gboolean gtk_selection_data_targets_include_uri  (GtkSelectionData  *selection_data);
-gboolean gtk_targets_include_text                (GdkAtom *targets,
-						  gint     n_targets);
-gboolean gtk_targets_include_image               (GdkAtom *targets,
-						  gint     n_targets,
-						  gboolean writable);
-gboolean gtk_targets_include_uri                 (GdkAtom *targets,
-						  gint     n_targets);
+gboolean gtk_targets_include_text                (GdkAtom       *targets,
+						  gint           n_targets);
+gboolean gtk_targets_include_rich_text           (GdkAtom       *targets,
+						  gint           n_targets,
+                                                  GtkTextBuffer *buffer);
+gboolean gtk_targets_include_image               (GdkAtom       *targets,
+						  gint           n_targets,
+						  gboolean       writable);
+gboolean gtk_targets_include_uri                 (GdkAtom       *targets,
+						  gint           n_targets);
 
 /* Called when a widget is destroyed */
 
@@ -186,6 +202,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
 
Index: gtk/gtktextbuffer.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtktextbuffer.c,v
retrieving revision 1.109
diff -u -p -r1.109 gtktextbuffer.c
--- gtk/gtktextbuffer.c	9 Dec 2005 17:26:26 -0000	1.109
+++ gtk/gtktextbuffer.c	7 Mar 2006 13:21:35 -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 "gtktextbufferrichtext.h"
 #include "gtktextbtree.h"
 #include "gtktextiterprivate.h"
 #include "gtkprivate.h"
@@ -42,6 +43,22 @@
 #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  *copy_target_list;
+  GtkTargetEntry *copy_target_entries;
+  gint            n_copy_target_entries;
+
+  GtkTargetList  *paste_target_list;
+  GtkTargetEntry *paste_target_entries;
+  gint            n_paste_target_entries;
+};
+
+
 typedef struct _ClipboardRequest ClipboardRequest;
 
 struct _ClipboardRequest
@@ -74,25 +91,18 @@ enum {
 
   /* Construct */
   PROP_TAG_TABLE,
-  
+
   /* Normal */
   PROP_TEXT,
-  PROP_HAS_SELECTION
-};
-
-enum {
-  TARGET_STRING,
-  TARGET_TEXT,
-  TARGET_COMPOUND_TEXT,
-  TARGET_UTF8_STRING,
-  TARGET_TEXT_BUFFER_CONTENTS
+  PROP_HAS_SELECTION,
+  PROP_COPY_TARGET_LIST,
+  PROP_PASTE_TARGET_LIST
 };
 
 static void gtk_text_buffer_init       (GtkTextBuffer      *tkxt_buffer);
 static void gtk_text_buffer_class_init (GtkTextBufferClass *klass);
 static void gtk_text_buffer_finalize   (GObject            *object);
 
-
 static void gtk_text_buffer_real_insert_text           (GtkTextBuffer     *buffer,
                                                         GtkTextIter       *iter,
                                                         const gchar       *text,
@@ -127,6 +137,8 @@ static void update_selection_clipboards 
 
 static GtkTextBuffer *create_clipboard_contents_buffer (GtkTextBuffer *buffer);
 
+static void gtk_text_buffer_free_target_lists     (GtkTextBuffer *buffer);
+
 static GObjectClass *parent_class = NULL;
 static guint signals[LAST_SIGNAL] = { 0 };
 
@@ -138,6 +150,8 @@ static void gtk_text_buffer_get_property
 				          guint            prop_id,
 				          GValue          *value,
 				          GParamSpec      *pspec);
+static void gtk_text_buffer_notify       (GObject         *object,
+                                          GParamSpec      *pspec);
 
 
 GType
@@ -177,6 +191,7 @@ gtk_text_buffer_class_init (GtkTextBuffe
   object_class->finalize = gtk_text_buffer_finalize;
   object_class->set_property = gtk_text_buffer_set_property;
   object_class->get_property = gtk_text_buffer_get_property;
+  object_class->notify       = gtk_text_buffer_notify;
  
   klass->insert_text = gtk_text_buffer_real_insert_text;
   klass->insert_pixbuf = gtk_text_buffer_real_insert_pixbuf;
@@ -227,7 +242,39 @@ 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:copy-target-list:
+   *
+   * The list of targets this buffer supports for clipboard copying
+   * and as DND source.
+   *
+   * Since: 2.10
+   */
+  g_object_class_install_property (object_class,
+                                   PROP_COPY_TARGET_LIST,
+                                   g_param_spec_boxed ("copy-target-list",
+                                                       P_("Copy target list"),
+                                                       P_("The list of targets this buffer supports for clipboard copying and DND source"),
+                                                       GTK_TYPE_TARGET_LIST,
+                                                       GTK_PARAM_READABLE));
+
+  /**
+   * GtkTextBuffer:paste-target-list:
+   *
+   * The list of targets this buffer supports for clipboard pasting
+   * and as DND destination.
+   *
+   * Since: 2.10
+   */
+  g_object_class_install_property (object_class,
+                                   PROP_PASTE_TARGET_LIST,
+                                   g_param_spec_boxed ("paste-target-list",
+                                                       P_("Paste target list"),
+                                                       P_("The list of targets this buffer supports for clipboard pasting and DND destination"),
+                                                       GTK_TYPE_TARGET_LIST,
+                                                       GTK_PARAM_READABLE));
 
   signals[INSERT_TEXT] =
     g_signal_new (I_("insert_text"),
@@ -378,7 +425,9 @@ gtk_text_buffer_class_init (GtkTextBuffe
                   NULL, NULL,
                   _gtk_marshal_VOID__VOID,
                   G_TYPE_NONE,
-                  0);  
+                  0);
+
+  g_type_class_add_private (object_class, sizeof (GtkTextBufferPrivate));
 }
 
 static void
@@ -386,6 +435,9 @@ gtk_text_buffer_init (GtkTextBuffer *buf
 {
   buffer->clipboard_contents_buffers = NULL;
   buffer->tag_table = NULL;
+
+  /* allow copying of arbiatray stuff in the internal rich text format */
+  gtk_text_buffer_register_serialize_tagset (buffer, NULL);
 }
 
 static void
@@ -428,9 +480,9 @@ gtk_text_buffer_set_property (GObject   
     case PROP_TAG_TABLE:
       set_table (text_buffer, g_value_get_object (value));
       break;
-      
+
     case PROP_TEXT:
-      gtk_text_buffer_set_text (text_buffer, 
+      gtk_text_buffer_set_text (text_buffer,
 				g_value_get_string (value), -1);
       break;
 
@@ -454,28 +506,48 @@ gtk_text_buffer_get_property (GObject   
     case PROP_TAG_TABLE:
       g_value_set_object (value, get_table (text_buffer));
       break;
-      
+
     case PROP_TEXT:
-    {
-      GtkTextIter start, end;
-      
-      gtk_text_buffer_get_start_iter (text_buffer, &start);
-      gtk_text_buffer_get_end_iter (text_buffer, &end);
-	    
-      g_value_set_string (value,
-			  gtk_text_buffer_get_text (text_buffer, &start, &end, FALSE));
-      break;
-    }
+      {
+        GtkTextIter start, end;
+
+        gtk_text_buffer_get_start_iter (text_buffer, &start);
+        gtk_text_buffer_get_end_iter (text_buffer, &end);
+
+        g_value_set_string (value,
+                            gtk_text_buffer_get_text (text_buffer,
+                                                      &start, &end, FALSE));
+        break;
+      }
 
     case PROP_HAS_SELECTION:
       g_value_set_boolean (value, text_buffer->has_selection);
       break;
 
+    case PROP_COPY_TARGET_LIST:
+      g_value_set_boxed (value, gtk_text_buffer_get_copy_target_list (text_buffer));
+      break;
+
+    case PROP_PASTE_TARGET_LIST:
+      g_value_set_boxed (value, gtk_text_buffer_get_paste_target_list (text_buffer));
+      break;
+
     default:
       break;
     }
 }
 
+static void
+gtk_text_buffer_notify (GObject    *object,
+                        GParamSpec *pspec)
+{
+  if (!strcmp (pspec->name, "copy-target-list") ||
+      !strcmp (pspec->name, "paste-target-list"))
+    {
+      gtk_text_buffer_free_target_lists (GTK_TEXT_BUFFER (object));
+    }
+}
+
 /**
  * gtk_text_buffer_new:
  * @table: a tag table, or NULL to create a new one
@@ -498,11 +570,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);
@@ -520,7 +595,9 @@ gtk_text_buffer_finalize (GObject *objec
     free_log_attr_cache (buffer->log_attr_cache);
 
   buffer->log_attr_cache = NULL;
-  
+
+  gtk_text_buffer_free_target_lists (buffer);
+
   G_OBJECT_CLASS (parent_class)->finalize (object);
 }
 
@@ -2840,22 +2917,36 @@ clipboard_get_selection_cb (GtkClipboard
 
   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 == GTK_TEXT_BUFFER_TARGET_INFO_BUFFER_CONTENTS)
         {
           /* Provide the address of the buffer; this will only be
            * used within-process
            */
           gtk_selection_data_set (selection_data,
-                                  gdk_atom_intern_static_string ("GTK_TEXT_BUFFER_CONTENTS"),
+                                  selection_data->target,
                                   8, /* bytes */
                                   (void*)&buffer,
                                   sizeof (buffer));
         }
+      else if (info == GTK_TEXT_BUFFER_TARGET_INFO_RICH_TEXT)
+        {
+          guint8 *str;
+          gsize   len;
+
+          str = gtk_text_buffer_serialize (buffer, buffer,
+                                           selection_data->target,
+                                           &start, &end, &len);
+
+          gtk_selection_data_set (selection_data,
+                                  selection_data->target,
+                                  8, /* bytes */
+                                  str, len);
+          g_free (str);
+        }
       else
         {
           gchar *str;
-          
+
           str = gtk_text_iter_get_visible_text (&start, &end);
           gtk_selection_data_set_text (selection_data, str, -1);
           g_free (str);
@@ -2870,8 +2961,11 @@ create_clipboard_contents_buffer (GtkTex
 
   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_data (G_OBJECT (contents), I_("gtk-text-buffer-clipboard-source"),
+                     buffer);
+  g_object_set_data (G_OBJECT (contents), I_("gtk-text-buffer-clipboard"),
+                     GINT_TO_POINTER (1));
+
   return contents;
 }
 
@@ -2882,31 +2976,50 @@ clipboard_get_contents_cb (GtkClipboard 
                            guint             info,
                            gpointer          data)
 {
-  GtkTextBuffer *contents;
+  GtkTextBuffer *contents = GTK_TEXT_BUFFER (data);
 
-  contents = GTK_TEXT_BUFFER (data);
-  
   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 == GTK_TEXT_BUFFER_TARGET_INFO_BUFFER_CONTENTS)
     {
       /* Provide the address of the clipboard buffer; this will only
        * be used within-process. OK to supply a NULL value for contents.
        */
       gtk_selection_data_set (selection_data,
-                              gdk_atom_intern_static_string ("GTK_TEXT_BUFFER_CONTENTS"),
+                              selection_data->target,
                               8, /* bytes */
                               (void*)&contents,
                               sizeof (contents));
     }
+  else if (info == GTK_TEXT_BUFFER_TARGET_INFO_RICH_TEXT)
+    {
+      GtkTextBuffer *clipboard_source_buffer;
+      GtkTextIter start, end;
+      guint8 *str;
+      gsize   len;
+
+      clipboard_source_buffer = g_object_get_data (G_OBJECT (contents),
+                                                   "gtk-text-buffer-clipboard-source");
+
+      gtk_text_buffer_get_bounds (contents, &start, &end);
+
+      str = gtk_text_buffer_serialize (clipboard_source_buffer, contents,
+                                       selection_data->target,
+                                       &start, &end, &len);
+
+      gtk_selection_data_set (selection_data,
+			      selection_data->target,
+			      8, /* bytes */
+			      str, len);
+      g_free (str);
+    }
   else
     {
       gchar *str;
       GtkTextIter start, end;
-      
+
       gtk_text_buffer_get_bounds (contents, &start, &end);
-      
+
       str = gtk_text_iter_get_visible_text (&start, &end);
       gtk_selection_data_set_text (selection_data, str, -1);
       g_free (str);
@@ -3052,7 +3165,8 @@ selection_data_get_buffer (GtkSelectionD
   if (gdk_window_get_window_type (owner) == GDK_WINDOW_FOREIGN)
     return NULL;
  
-  if (selection_data->type != gdk_atom_intern_static_string ("GTK_TEXT_BUFFER_CONTENTS"))
+  if (selection_data->type !=
+      gdk_atom_intern_static_string ("GTK_TEXT_BUFFER_CONTENTS"))
     return NULL;
 
   if (selection_data->length != sizeof (src_buffer))
@@ -3100,6 +3214,62 @@ restore_iter (const GtkTextIter *iter,
 #endif
 
 static void
+clipboard_rich_text_received (GtkClipboard *clipboard,
+                              GdkAtom       format,
+                              const guint8 *text,
+                              gsize         length,
+                              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);
+
+  if (text != NULL && length > 0)
+    {
+      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 (request_data->buffer,
+                                                request_data->buffer,
+                                                format,
+                                                &insert_point,
+                                                text, length,
+                                                &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,7 +3315,8 @@ clipboard_clipboard_buffer_received (Gtk
 {
   ClipboardRequest *request_data = data;
   GtkTextBuffer *src_buffer;
-  
+  GtkTextBufferPrivate *priv;
+
   src_buffer = selection_data_get_buffer (selection_data, request_data); 
 
   if (src_buffer)
@@ -3155,7 +3326,7 @@ clipboard_clipboard_buffer_received (Gtk
       if (g_object_get_data (G_OBJECT (src_buffer), "gtk-text-buffer-clipboard"))
 	{
 	  gtk_text_buffer_get_bounds (src_buffer, &start, &end);
-      
+
 	  paste_from_buffer (request_data, src_buffer,
 			     &start, &end);
 	}
@@ -3168,21 +3339,27 @@ clipboard_clipboard_buffer_received (Gtk
     }
   else
     {
-      /* Request the text selection instead */
-      gtk_clipboard_request_text (clipboard,
-                                  clipboard_text_received,
-                                  data);
+      priv = GTK_TEXT_BUFFER_GET_PRIVATE (request_data->buffer);
+
+      if (gtk_clipboard_wait_is_rich_text_available (clipboard,
+                                                     request_data->buffer))
+        {
+          /* Request rich text */
+          gtk_clipboard_request_rich_text (clipboard,
+                                           request_data->buffer,
+                                           clipboard_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 +3369,13 @@ typedef struct
 static void
 update_selection_clipboards (GtkTextBuffer *buffer)
 {
-  GSList *tmp_list = buffer->selection_clipboards;
+  GtkTextBufferPrivate *priv;
+  GSList               *tmp_list = buffer->selection_clipboards;
+
+  priv = GTK_TEXT_BUFFER_GET_PRIVATE (buffer);
+
+  gtk_text_buffer_get_copy_target_list (buffer);
+
   while (tmp_list)
     {
       GtkTextIter start;
@@ -3214,7 +3397,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->copy_target_entries,
+                                             priv->n_copy_target_entries,
 					     clipboard_get_selection_cb,
 					     clipboard_clear_selection_cb,
 					     G_OBJECT (buffer)))
@@ -3525,6 +3710,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
@@ -3534,7 +3721,11 @@ cut_or_copy (GtkTextBuffer *buffer,
    */
   GtkTextIter start;
   GtkTextIter end;
-  
+
+  priv = GTK_TEXT_BUFFER_GET_PRIVATE (buffer);
+
+  gtk_text_buffer_get_copy_target_list (buffer);
+
   if (!gtk_text_buffer_get_selection_bounds (buffer, &start, &end))
     {
       /* Let's try the anchor thing */
@@ -3560,14 +3751,18 @@ 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->copy_target_entries,
+                                        priv->n_copy_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->copy_target_entries + 1,
+                                     priv->n_copy_target_entries - 1);
+
       if (delete_region_after)
         {
           if (interactive)
@@ -3697,6 +3892,126 @@ 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_lists (GtkTextBuffer *buffer)
+{
+  GtkTextBufferPrivate *priv = GTK_TEXT_BUFFER_GET_PRIVATE (buffer);
+
+  if (priv->copy_target_list)
+    {
+      gtk_target_list_unref (priv->copy_target_list);
+      priv->copy_target_list = NULL;
+
+      gtk_target_table_free (priv->copy_target_entries,
+                             priv->n_copy_target_entries);
+      priv->copy_target_entries = NULL;
+      priv->n_copy_target_entries = 0;
+    }
+
+  if (priv->paste_target_list)
+    {
+      gtk_target_list_unref (priv->paste_target_list);
+      priv->paste_target_list = NULL;
+
+      gtk_target_table_free (priv->paste_target_entries,
+                             priv->n_paste_target_entries);
+      priv->paste_target_entries = NULL;
+      priv->n_paste_target_entries = 0;
+    }
+}
+
+static GtkTargetList *
+gtk_text_buffer_get_target_list (GtkTextBuffer   *buffer,
+                                 gboolean         deserializable,
+                                 GtkTargetEntry **entries,
+                                 gint            *n_entries)
+{
+  GtkTargetList *target_list;
+
+  target_list = gtk_target_list_new (NULL, 0);
+
+  gtk_target_list_add (target_list,
+                       gdk_atom_intern_static_string ("GTK_TEXT_BUFFER_CONTENTS"),
+                       GTK_TARGET_SAME_APP,
+                       GTK_TEXT_BUFFER_TARGET_INFO_BUFFER_CONTENTS);
+
+  gtk_target_list_add_rich_text_targets (target_list,
+                                         GTK_TEXT_BUFFER_TARGET_INFO_RICH_TEXT,
+                                         deserializable,
+                                         buffer);
+
+  gtk_target_list_add_text_targets (target_list,
+                                    GTK_TEXT_BUFFER_TARGET_INFO_TEXT);
+
+  *entries = gtk_target_table_new_from_list (target_list, n_entries);
+
+  return target_list;
+}
+
+/**
+ * gtk_text_buffer_get_copy_target_list:
+ * @buffer: a #GtkTextBuffer
+ *
+ * This function returns the list of targets this text buffer can
+ * provide for copying and as DND source. The targets in the list are
+ * added with %info values from the #GtkTextBufferTargetInfo enum,
+ * using gtk_target_list_add_rich_text_targets() and
+ * gtk_target_list_add_text_targets()
+ *
+ * Return value: the #GtkTargetList
+ *
+ * Since: 2.10
+ **/
+GtkTargetList *
+gtk_text_buffer_get_copy_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->copy_target_list)
+    priv->copy_target_list =
+      gtk_text_buffer_get_target_list (buffer, FALSE,
+                                       &priv->copy_target_entries,
+                                       &priv->n_copy_target_entries);
+
+  return priv->copy_target_list;
+}
+
+/**
+ * gtk_text_buffer_get_paste_target_list:
+ * @buffer: a #GtkTextBuffer
+ *
+ * This function returns the list of targets this text buffer supports
+ * for pasting and as DND destination. The targets in the list are
+ * added with %info values from the #GtkTextBufferTargetInfo enum,
+ * using gtk_target_list_add_rich_text_targets() and
+ * gtk_target_list_add_text_targets()
+ *
+ * Return value: the #GtkTargetList
+ *
+ * Since: 2.10
+ **/
+GtkTargetList *
+gtk_text_buffer_get_paste_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->paste_target_list)
+    priv->paste_target_list =
+      gtk_text_buffer_get_target_list (buffer, TRUE,
+                                       &priv->paste_target_entries,
+                                       &priv->n_paste_target_entries);
+
+  return priv->paste_target_list;
 }
 
 /*
Index: gtk/gtktextbuffer.h
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtktextbuffer.h,v
retrieving revision 1.38
diff -u -p -r1.38 gtktextbuffer.h
--- gtk/gtktextbuffer.h	7 Oct 2005 03:38:56 -0000	1.38
+++ gtk/gtktextbuffer.h	7 Mar 2006 13:21:35 -0000
@@ -41,6 +41,16 @@ G_BEGIN_DECLS
  * GtkTextBTree is the PRIVATE internal representation of it.
  */
 
+/* these values are used as "info" for the targets contained in the
+ * lists returned by gtk_text_buffer_get_copy,paste_target_list()
+ */
+typedef enum
+{
+  GTK_TEXT_BUFFER_TARGET_INFO_BUFFER_CONTENTS,
+  GTK_TEXT_BUFFER_TARGET_INFO_RICH_TEXT,
+  GTK_TEXT_BUFFER_TARGET_INFO_TEXT
+} GtkTextBufferTargetInfo;
+
 typedef struct _GtkTextBTree GtkTextBTree;
 
 typedef struct _GtkTextLogAttrCache GtkTextLogAttrCache;
@@ -366,6 +376,9 @@ gboolean        gtk_text_buffer_delete_s
 /* Called to specify atomic user actions, used to implement undo */
 void            gtk_text_buffer_begin_user_action       (GtkTextBuffer *buffer);
 void            gtk_text_buffer_end_user_action         (GtkTextBuffer *buffer);
+
+GtkTargetList * gtk_text_buffer_get_copy_target_list    (GtkTextBuffer *buffer);
+GtkTargetList * gtk_text_buffer_get_paste_target_list   (GtkTextBuffer *buffer);
 
 /* INTERNAL private stuff */
 void            _gtk_text_buffer_spew                  (GtkTextBuffer      *buffer);
Index: gtk/gtktextutil.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtktextutil.c,v
retrieving revision 1.15
diff -u -p -r1.15 gtktextutil.c
--- gtk/gtktextutil.c	13 Sep 2005 19:57:42 -0000	1.15
+++ gtk/gtktextutil.c	7 Mar 2006 13:21:36 -0000
@@ -26,12 +26,19 @@
 
 #include <config.h>
 #include "gtktextutil.h"
-#include "gtkintl.h"
+#include "gtktextview.h"
+
+#define GTK_TEXT_USE_INTERNAL_UNSUPPORTED_API
+
+#include "gtktextdisplay.h"
+#include "gtktextbuffer.h"
 #include "gtkmenuitem.h"
+#include "gtkintl.h"
 #include "gtkalias.h"
 
 #define DRAG_ICON_MAX_WIDTH 250
-#define DRAG_ICON_LAYOUT_BORDER 2
+#define DRAG_ICON_MAX_HEIGHT 250
+#define DRAG_ICON_LAYOUT_BORDER 5
 #define DRAG_ICON_MAX_LINES 7
 #define ELLIPSIS_CHARACTER "\xe2\x80\xa6"
 
@@ -177,7 +184,7 @@ limit_layout_lines (PangoLayout *layout)
  *
  * Creates a drag and drop icon from @text.
  **/
-GdkPixmap*
+GdkPixmap *
 _gtk_text_util_create_drag_icon (GtkWidget *widget, 
                                  gchar     *text,
                                  gsize      len)
@@ -237,4 +244,125 @@ _gtk_text_util_create_drag_icon (GtkWidg
   g_object_unref (layout);
 
   return drawable;
+}
+
+static void
+gtk_text_view_set_attributes_from_style (GtkTextView        *text_view,
+                                         GtkTextAttributes  *values,
+                                         GtkStyle           *style)
+{
+  values->appearance.bg_color = style->base[GTK_STATE_NORMAL];
+  values->appearance.fg_color = style->text[GTK_STATE_NORMAL];
+
+  if (values->font)
+    pango_font_description_free (values->font);
+
+  values->font = pango_font_description_copy (style->font_desc);
+}
+
+GdkPixmap *
+_gtk_text_util_create_rich_drag_icon (GtkWidget     *widget,
+                                      GtkTextBuffer *buffer,
+                                      GtkTextIter   *start,
+                                      GtkTextIter   *end)
+{
+  GdkDrawable       *drawable = NULL;
+  gint               pixmap_height, pixmap_width;
+  gint               layout_width, layout_height;
+  GtkTextBuffer     *new_buffer;
+  GtkTextLayout     *layout;
+  GtkTextAttributes *style;
+  PangoContext      *ltr_context, *rtl_context;
+  GtkTextIter        iter;
+
+   g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
+   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
+   g_return_val_if_fail (start != NULL, NULL);
+   g_return_val_if_fail (end != NULL, NULL);
+
+   new_buffer = gtk_text_buffer_new (gtk_text_buffer_get_tag_table (buffer));
+   gtk_text_buffer_get_start_iter (new_buffer, &iter);
+
+   gtk_text_buffer_insert_range (new_buffer, &iter, start, end);
+
+   gtk_text_buffer_get_start_iter (new_buffer, &iter);
+
+   layout = gtk_text_layout_new ();
+
+   ltr_context = gtk_widget_create_pango_context (widget);
+   pango_context_set_base_dir (ltr_context, PANGO_DIRECTION_LTR);
+   rtl_context = gtk_widget_create_pango_context (widget);
+   pango_context_set_base_dir (rtl_context, PANGO_DIRECTION_RTL);
+
+   gtk_text_layout_set_contexts (layout, ltr_context, rtl_context);
+
+   g_object_unref (ltr_context);
+   g_object_unref (rtl_context);
+
+   style = gtk_text_attributes_new ();
+
+   layout_width = widget->allocation.width;
+
+   if (GTK_IS_TEXT_VIEW (widget))
+     {
+       gtk_widget_ensure_style (widget);
+       gtk_text_view_set_attributes_from_style (GTK_TEXT_VIEW (widget),
+                                                style, widget->style);
+
+       layout_width = layout_width
+         - gtk_text_view_get_border_window_size (GTK_TEXT_VIEW (widget), GTK_TEXT_WINDOW_LEFT)
+         - gtk_text_view_get_border_window_size (GTK_TEXT_VIEW (widget), GTK_TEXT_WINDOW_RIGHT);
+     }
+
+   style->direction = gtk_widget_get_direction (widget);
+   style->wrap_mode = PANGO_WRAP_WORD_CHAR;
+
+   gtk_text_layout_set_default_style (layout, style);
+   gtk_text_attributes_unref (style);
+
+   gtk_text_layout_set_buffer (layout, new_buffer);
+   gtk_text_layout_set_cursor_visible (layout, FALSE);
+   gtk_text_layout_set_screen_width (layout, layout_width);
+
+   gtk_text_layout_validate (layout, DRAG_ICON_MAX_HEIGHT);
+   gtk_text_layout_get_size (layout, &layout_width, &layout_height);
+
+   g_print ("%s: layout size %d %d\n", G_STRFUNC, layout_width, layout_height);
+
+   layout_width = MIN (layout_width, DRAG_ICON_MAX_WIDTH);
+   layout_height = MIN (layout_height, DRAG_ICON_MAX_HEIGHT);
+
+   pixmap_width  = layout_width + DRAG_ICON_LAYOUT_BORDER * 2;
+   pixmap_height = layout_height + DRAG_ICON_LAYOUT_BORDER * 2;
+
+   g_print ("%s: pixmap size %d %d\n", G_STRFUNC, pixmap_width, pixmap_height);
+
+   drawable = gdk_pixmap_new (widget->window,
+                              pixmap_width  + 2, pixmap_height + 2, -1);
+
+   gdk_draw_rectangle (drawable,
+                       widget->style->base_gc [GTK_WIDGET_STATE (widget)],
+                       TRUE,
+                       0, 0,
+                       pixmap_width + 1,
+                       pixmap_height + 1);
+
+   gtk_text_layout_draw (layout, widget, drawable,
+                         widget->style->text_gc [GTK_WIDGET_STATE (widget)],
+                         - (1 + DRAG_ICON_LAYOUT_BORDER),
+                         - (1 + DRAG_ICON_LAYOUT_BORDER),
+                         0, 0,
+                         pixmap_width, pixmap_height, NULL);
+
+   gdk_draw_rectangle (drawable,
+                       widget->style->black_gc,
+                       FALSE,
+                       0, 0,
+                       pixmap_width + 1,
+                       pixmap_height + 1);
+
+   g_object_unref (layout);
+   g_object_unref (new_buffer);
+
+   return drawable;
 }
Index: gtk/gtktextutil.h
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtktextutil.h,v
retrieving revision 1.3
diff -u -p -r1.3 gtktextutil.h
--- gtk/gtktextutil.h	11 Jul 2005 17:51:54 -0000	1.3
+++ gtk/gtktextutil.h	7 Mar 2006 13:21:36 -0000
@@ -31,6 +31,7 @@
 #include <gtk/gtkwidget.h>
 #include <gtk/gtkmenushell.h>
 #include <gtk/gtkeditable.h>
+#include <gtk/gtktextbuffer.h>
 
 
 G_BEGIN_DECLS
@@ -47,8 +48,12 @@ void _gtk_text_util_append_special_char_
 
 G_END_DECLS
 
-GdkPixmap* _gtk_text_util_create_drag_icon  (GtkWidget *widget, 
-					     gchar     *text,
-					     gsize      len);
+GdkPixmap* _gtk_text_util_create_drag_icon      (GtkWidget     *widget,
+                                                 gchar         *text,
+                                                 gsize          len);
+GdkPixmap* _gtk_text_util_create_rich_drag_icon (GtkWidget     *widget,
+                                                 GtkTextBuffer *buffer,
+                                                 GtkTextIter   *start,
+                                                 GtkTextIter   *end);
 
 #endif /* __GTK_TEXT_UTIL_H__ */
Index: gtk/gtktextview.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtktextview.c,v
retrieving revision 1.305
diff -u -p -r1.305 gtktextview.c
--- gtk/gtktextview.c	7 Mar 2006 02:05:02 -0000	1.305
+++ gtk/gtktextview.c	7 Mar 2006 13:21:38 -0000
@@ -39,6 +39,7 @@
 #include "gtkseparatormenuitem.h"
 #include "gtksettings.h"
 #include "gtkstock.h"
+#include "gtktextbufferrichtext.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::paste-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))
 	{
@@ -5984,21 +5990,6 @@ gtk_text_view_reset_im_context (GtkTextV
     }
 }
 
-static gchar*
-_gtk_text_view_get_selected_text (GtkTextView *text_view)
-{
-  GtkTextBuffer *buffer;
-  GtkTextIter    start, end;
-  gchar         *text = NULL;
-
-  buffer = gtk_text_view_get_buffer (text_view);
-
-  if (gtk_text_buffer_get_selection_bounds (buffer, &start, &end))
-    text = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
-
-  return text;
-}
-
 /*
  * DND feature
  */
@@ -6008,29 +5999,30 @@ drag_begin_cb (GtkWidget      *widget,
                GdkDragContext *context,
                gpointer        data)
 {
-  GtkTextView *text_view;
-  gchar *text;
-  GdkPixmap *pixmap = NULL;
+  GtkTextView   *text_view = GTK_TEXT_VIEW (widget);
+  GtkTextBuffer *buffer = gtk_text_view_get_buffer (text_view);
+  GtkTextIter    start;
+  GtkTextIter    end;
+  GdkPixmap     *pixmap = NULL;
 
   g_signal_handlers_disconnect_by_func (widget, drag_begin_cb, NULL);
 
-  text_view = GTK_TEXT_VIEW (widget);
-
-  text   = _gtk_text_view_get_selected_text (text_view);
-  pixmap = _gtk_text_util_create_drag_icon (widget, text, -1);
+  if (gtk_text_buffer_get_selection_bounds (buffer, &start, &end))
+    pixmap = _gtk_text_util_create_rich_drag_icon (widget, buffer, &start, &end);
 
   if (pixmap)
-    gtk_drag_set_icon_pixmap (context,
-                              gdk_drawable_get_colormap (pixmap),
-                              pixmap,
-                              NULL,
-                              -2, -2);
+    {
+      gtk_drag_set_icon_pixmap (context,
+                                gdk_drawable_get_colormap (pixmap),
+                                pixmap,
+                                NULL,
+                                -2, -2);
+      g_object_unref (pixmap);
+    }
   else
-    gtk_drag_set_icon_default (context);
-  
-  if (pixmap)
-    g_object_unref (pixmap);
-  g_free (text);
+    {
+      gtk_drag_set_icon_default (context);
+    }
 }
 
 static void
@@ -6038,23 +6030,19 @@ gtk_text_view_start_selection_dnd (GtkTe
                                    const GtkTextIter *iter,
                                    GdkEventMotion    *event)
 {
-  GtkTargetList  *target_list;
+  GtkTargetList *target_list;
 
   text_view->drag_start_x = -1;
   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);
 
-  g_signal_connect (text_view, "drag-begin", 
+  target_list = gtk_text_buffer_get_copy_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 +6065,49 @@ gtk_text_view_drag_data_get (GtkWidget  
                              guint             info,
                              guint             time)
 {
-  GtkTextView *text_view;
-
-  text_view = GTK_TEXT_VIEW (widget);
+  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"))
+  if (info == GTK_TEXT_BUFFER_TARGET_INFO_BUFFER_CONTENTS)
     {
-      GtkTextBuffer *buffer = gtk_text_view_get_buffer (text_view);
-
       gtk_selection_data_set (selection_data,
                               gdk_atom_intern_static_string ("GTK_TEXT_BUFFER_CONTENTS"),
                               8, /* bytes */
                               (void*)&buffer,
                               sizeof (buffer));
     }
-  else
+  else if (info == GTK_TEXT_BUFFER_TARGET_INFO_RICH_TEXT)
     {
-      gchar *str;
       GtkTextIter start;
       GtkTextIter end;
+      guint8 *str = NULL;
+      gsize len;
+
+      if (gtk_text_buffer_get_selection_bounds (buffer, &start, &end))
+        {
+          /* Extract the selected text */
+          str = gtk_text_buffer_serialize (buffer, buffer,
+                                           selection_data->target,
+                                           &start, &end,
+                                           &len);
+        }
 
-      str = NULL;
+      if (str)
+        {
+          gtk_selection_data_set (selection_data,
+                                  selection_data->target,
+                                  8, /* bytes */
+                                  (guchar *) str, len);
+          g_free (str);
+        }
+    }
+  else
+    {
+      GtkTextIter start;
+      GtkTextIter end;
+      gchar *str = NULL;
 
-      if (gtk_text_buffer_get_selection_bounds (get_buffer (text_view),
-                                                &start, &end))
+      if (gtk_text_buffer_get_selection_bounds (buffer, &start, &end))
         {
           /* Extract the selected text */
           str = gtk_text_iter_get_visible_text (&start, &end);
@@ -6179,7 +6186,7 @@ gtk_text_view_drag_motion (GtkWidget    
       /* can't accept any of the offered targets */
     }                                 
   else if (gtk_text_buffer_get_selection_bounds (get_buffer (text_view),
-                                            &start, &end) &&
+                                                 &start, &end) &&
            gtk_text_iter_compare (&newplace, &start) >= 0 &&
            gtk_text_iter_compare (&newplace, &end) <= 0)
     {
@@ -6284,14 +6291,14 @@ insert_text_data (GtkTextView      *text
                   GtkTextIter      *drop_point,
                   GtkSelectionData *selection_data)
 {
-  gchar *str;
+  guchar *str;
 
   str = gtk_selection_data_get_text (selection_data);
 
   if (str)
     {
       gtk_text_buffer_insert_interactive (get_buffer (text_view),
-                                          drop_point, str, -1,
+                                          drop_point, (gchar *) str, -1,
                                           text_view->editable);
       g_free (str);
     }
@@ -6329,7 +6336,7 @@ 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 (info == GTK_TEXT_BUFFER_TARGET_INFO_BUFFER_CONTENTS)
     {
       GtkTextBuffer *src_buffer = NULL;
       GtkTextIter start, end;
@@ -6347,7 +6354,38 @@ gtk_text_view_drag_data_received (GtkWid
 
       if (gtk_text_buffer_get_tag_table (src_buffer) !=
           gtk_text_buffer_get_tag_table (buffer))
-        copy_tags = FALSE;
+        {
+          /*  try to find a suitable rich text target instead  */
+          GdkAtom *atoms;
+          gint     n_atoms;
+          GList   *list;
+          GdkAtom  target = GDK_NONE;
+
+          copy_tags = FALSE;
+
+          atoms = gtk_text_buffer_get_deserialize_formats (buffer, &n_atoms);
+
+          for (list = context->targets; list; list = g_list_next (list))
+            {
+              gint i;
+
+              for (i = 0; i < n_atoms; i++)
+                if (GUINT_TO_POINTER (atoms[i]) == list->data)
+                  {
+                    target = atoms[i];
+                    break;
+                  }
+            }
+
+          g_free (atoms);
+
+          if (target != GDK_NONE)
+            {
+              gtk_drag_get_data (widget, context, target, time);
+              gtk_text_buffer_end_user_action (buffer);
+              return;
+            }
+        }
 
       if (gtk_text_buffer_get_selection_bounds (src_buffer,
                                                 &start,
@@ -6371,9 +6409,28 @@ gtk_text_view_drag_data_received (GtkWid
             }
         }
     }
+  else if (selection_data->length > 0 &&
+           info == GTK_TEXT_BUFFER_TARGET_INFO_RICH_TEXT)
+    {
+      gboolean retval;
+      GError *error = NULL;
+
+      retval = gtk_text_buffer_deserialize (buffer, buffer,
+                                            selection_data->target,
+                                            &drop_point,
+                                            (guint8 *) selection_data->data,
+                                            selection_data->length,
+                                            &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);
- 
+
  done:
   gtk_drag_finish (context, success,
 		   success && context->action == GDK_ACTION_MOVE,
@@ -6823,6 +6880,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_paste_target_list (buffer));
 }
 
 static void
Index: tests/testtext.c
===================================================================
RCS file: /cvs/gnome/gtk+/tests/testtext.c,v
retrieving revision 1.79
diff -u -p -r1.79 testtext.c
--- tests/testtext.c	13 Jul 2005 05:44:22 -0000	1.79
+++ tests/testtext.c	7 Mar 2006 13:21:39 -0000
@@ -1282,6 +1282,267 @@ do_properties (gpointer callback_data,
   create_prop_editor (G_OBJECT (view->text_view), 0);
 }
 
+static void
+rich_text_store_populate (GtkListStore  *store,
+                          GtkTextBuffer *buffer,
+                          gboolean       deserialize)
+{
+  GdkAtom *formats;
+  gint     n_formats;
+  gint     i;
+
+  gtk_list_store_clear (store);
+
+  if (deserialize)
+    formats = gtk_text_buffer_get_deserialize_formats (buffer, &n_formats);
+  else
+    formats = gtk_text_buffer_get_serialize_formats (buffer, &n_formats);
+
+  for (i = 0; i < n_formats; i++)
+    {
+      GtkTreeIter  iter;
+      gchar       *mime_type;
+      gboolean     can_create_tags = FALSE;
+
+      mime_type = gdk_atom_name (formats[i]);
+
+      if (deserialize)
+        can_create_tags =
+          gtk_text_buffer_deserialize_get_can_create_tags (buffer, formats[i]);
+
+      gtk_list_store_append (store, &iter);
+      gtk_list_store_set (store, &iter,
+                          0, formats[i],
+                          1, mime_type,
+                          2, can_create_tags,
+                          -1);
+
+      g_free (mime_type);
+    }
+
+  g_free (formats);
+}
+
+static void
+rich_text_paste_target_list_notify (GtkTextBuffer    *buffer,
+                                    const GParamSpec *pspec,
+                                    GtkListStore     *store)
+{
+  rich_text_store_populate (store, buffer, TRUE);
+}
+
+static void
+rich_text_copy_target_list_notify (GtkTextBuffer    *buffer,
+                                   const GParamSpec *pspec,
+                                   GtkListStore     *store)
+{
+  rich_text_store_populate (store, buffer, FALSE);
+}
+
+static void
+rich_text_can_create_tags_toggled (GtkCellRendererToggle *toggle,
+                                   const gchar           *path,
+                                   GtkTreeModel          *model)
+{
+  GtkTreeIter iter;
+
+  if (gtk_tree_model_get_iter_from_string (model, &iter, path))
+    {
+      GtkTextBuffer *buffer;
+      GdkAtom        format;
+      gboolean       can_create_tags;
+
+      buffer = g_object_get_data (G_OBJECT (model), "buffer");
+
+      gtk_tree_model_get (model, &iter,
+                          0, &format,
+                          2, &can_create_tags,
+                          -1);
+
+      gtk_text_buffer_deserialize_set_can_create_tags (buffer, format,
+                                                       !can_create_tags);
+
+      gtk_list_store_set (GTK_LIST_STORE (model), &iter,
+                          2, !can_create_tags,
+                          -1);
+    }
+}
+
+static void
+rich_text_unregister_clicked (GtkWidget   *button,
+                              GtkTreeView *tv)
+{
+  GtkTreeSelection *sel = gtk_tree_view_get_selection (tv);
+  GtkTreeModel     *model;
+  GtkTreeIter       iter;
+
+  if (gtk_tree_selection_get_selected (sel, &model, &iter))
+    {
+      GtkTextBuffer *buffer;
+      gboolean       deserialize;
+      GdkAtom        format;
+
+      buffer = g_object_get_data (G_OBJECT (model), "buffer");
+      deserialize = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (model),
+                                                        "deserialize"));
+
+      gtk_tree_model_get (model, &iter,
+                          0, &format,
+                          -1);
+
+      if (deserialize)
+        gtk_text_buffer_unregister_deserialize_format (buffer, format);
+      else
+        gtk_text_buffer_unregister_serialize_format (buffer, format);
+    }
+}
+
+static void
+rich_text_register_clicked (GtkWidget   *button,
+                            GtkTreeView *tv)
+{
+  GtkWidget *dialog;
+  GtkWidget *label;
+  GtkWidget *entry;
+
+  dialog = gtk_dialog_new_with_buttons ("Register new Tagset",
+                                        GTK_WINDOW (gtk_widget_get_toplevel (button)),
+                                        GTK_DIALOG_DESTROY_WITH_PARENT,
+                                        GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+                                        GTK_STOCK_OK,     GTK_RESPONSE_OK,
+                                        NULL);
+  label = gtk_label_new ("Enter tagset name or leave blank for "
+                         "unrestricted internal format:");
+  gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), label,
+                      FALSE, FALSE, 0);
+
+  entry = gtk_entry_new ();
+  gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), entry,
+                      FALSE, FALSE, 0);
+
+  gtk_widget_show_all (dialog);
+
+  if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK)
+    {
+      GtkTreeModel  *model  = gtk_tree_view_get_model (tv);
+      GtkTextBuffer *buffer = g_object_get_data (G_OBJECT (model), "buffer");
+      const gchar   *tagset = gtk_entry_get_text (GTK_ENTRY (entry));
+      gboolean       deserialize;
+
+      deserialize = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (model),
+                                                        "deserialize"));
+
+      if (tagset && ! strlen (tagset))
+        tagset = NULL;
+
+      if (deserialize)
+        gtk_text_buffer_register_deserialize_tagset (buffer, tagset);
+      else
+        gtk_text_buffer_register_serialize_tagset (buffer, tagset);
+    }
+
+  gtk_widget_destroy (dialog);
+}
+
+static void
+do_rich_text (gpointer callback_data,
+              guint deserialize,
+              GtkWidget *widget)
+{
+  View *view = view_from_widget (widget);
+  GtkTextBuffer *buffer;
+  GtkWidget *dialog;
+  GtkWidget *tv;
+  GtkWidget *sw;
+  GtkWidget *hbox;
+  GtkWidget *button;
+  GtkListStore *store;
+
+  buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view->text_view));
+
+  dialog = gtk_dialog_new_with_buttons (deserialize ?
+                                        "Rich Text Paste & Drop" :
+                                        "Rich Text Copy & Drag",
+                                        GTK_WINDOW (view->window),
+                                        GTK_DIALOG_DESTROY_WITH_PARENT,
+                                        GTK_STOCK_CLOSE, 0,
+                                        NULL);
+  g_signal_connect (dialog, "response",
+                    G_CALLBACK (gtk_widget_destroy),
+                    NULL);
+
+  store = gtk_list_store_new (3,
+                              G_TYPE_POINTER,
+                              G_TYPE_STRING,
+                              G_TYPE_BOOLEAN);
+
+  g_object_set_data (G_OBJECT (store), "buffer", buffer);
+  g_object_set_data (G_OBJECT (store), "deserialize",
+                     GUINT_TO_POINTER (deserialize));
+
+  tv = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
+  g_object_unref (store);
+
+  gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (tv),
+                                               0, "Rich Text Format",
+                                               gtk_cell_renderer_text_new (),
+                                               "text", 1,
+                                               NULL);
+
+  if (deserialize)
+    {
+      GtkCellRenderer *renderer = gtk_cell_renderer_toggle_new ();
+
+      gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (tv),
+                                                   1, "Can Create Tags",
+                                                   renderer,
+                                                   "active", 2,
+                                                   NULL);
+
+      g_signal_connect (renderer, "toggled",
+                        G_CALLBACK (rich_text_can_create_tags_toggled),
+                        store);
+    }
+
+  sw = gtk_scrolled_window_new (NULL, NULL);
+  gtk_widget_set_size_request (sw, 300, 100);
+  gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), sw);
+
+  gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (sw), tv);
+
+  hbox = gtk_hbox_new (FALSE, 6);
+  gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), hbox,
+                      FALSE, FALSE, 0);
+
+  button = gtk_button_new_with_label ("Unregister Selected Format");
+  gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
+
+  g_signal_connect (button, "clicked",
+                    G_CALLBACK (rich_text_unregister_clicked),
+                    tv);
+
+  button = gtk_button_new_with_label ("Register New Tagset\n"
+                                      "for the Internal Format");
+  gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
+
+  g_signal_connect (button, "clicked",
+                    G_CALLBACK (rich_text_register_clicked),
+                    tv);
+
+  if (deserialize)
+    g_signal_connect_object (buffer, "notify::paste-target-list",
+                             G_CALLBACK (rich_text_paste_target_list_notify),
+                             G_OBJECT (store), 0);
+  else
+    g_signal_connect_object (buffer, "notify::copy-target-list",
+                             G_CALLBACK (rich_text_copy_target_list_notify),
+                             G_OBJECT (store), 0);
+
+  rich_text_store_populate (store, buffer, deserialize);
+
+  gtk_widget_show_all (dialog);
+}
+
 enum
 {
   RESPONSE_FORWARD,
@@ -1695,8 +1956,10 @@ static GtkItemFactoryEntry menu_items[] 
   { "/Attributes/Default tabs",   	  NULL,         do_apply_tabs, TRUE, NULL },
   { "/Attributes/Color cycles",   	  NULL,         do_apply_colors, TRUE, NULL },
   { "/Attributes/No colors",   	          NULL,         do_apply_colors, FALSE, NULL },
-  { "/Attributes/Remove all tags",       NULL, do_remove_tags, 0, NULL },
-  { "/Attributes/Properties",       NULL, do_properties, 0, NULL },
+  { "/Attributes/Remove all tags",        NULL, do_remove_tags, 0, NULL },
+  { "/Attributes/Properties",             NULL, do_properties, 0, NULL },
+  { "/Attributes/Rich Text copy & drag",  NULL, do_rich_text, 0, NULL },
+  { "/Attributes/Rich Text paste & drop", NULL, do_rich_text, 1, NULL },
   { "/_Test",   	 NULL,         NULL,           0, "<Branch>" },
   { "/Test/_Example",  	 NULL,         do_example,  0, NULL },
   { "/Test/_Insert and scroll", NULL,         do_insert_and_scroll,  0, NULL },
