Index: gtk/Makefile.am
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/Makefile.am,v
retrieving revision 1.292
diff -u -p -r1.292 Makefile.am
--- gtk/Makefile.am	29 Jan 2006 04:00:43 -0000	1.292
+++ gtk/Makefile.am	3 Feb 2006 14:56:36 -0000
@@ -227,6 +227,7 @@ gtk_public_h_sources =          \
 	gtkradiotoolbutton.h	\
 	gtkrange.h		\
 	gtkrc.h			\
+	gtkrichtext.h		\
 	gtkruler.h		\
 	gtkscale.h		\
 	gtkscrollbar.h		\
@@ -458,6 +459,7 @@ gtk_c_sources =                 \
 	gtkrange.c		\
 	gtkrbtree.c 		\
 	gtkrc.c			\
+	gtkrichtext.c		\
 	gtkruler.c		\
 	gtkscale.c		\
 	gtkscrollbar.c		\
@@ -481,6 +483,8 @@ gtk_c_sources =                 \
 	gtktext.c		\
 	gtktextbtree.c		\
 	gtktextbuffer.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	3 Feb 2006 14:56:36 -0000
@@ -139,6 +139,7 @@
 #include <gtk/gtkradiotoolbutton.h>
 #include <gtk/gtkrange.h>
 #include <gtk/gtkrc.h>
+#include <gtk/gtkrichtext.h>
 #include <gtk/gtkruler.h>
 #include <gtk/gtkscale.h>
 #include <gtk/gtkscrollbar.h>
Index: gtk/gtk.symbols
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtk.symbols,v
retrieving revision 1.84
diff -u -p -r1.84 gtk.symbols
--- gtk/gtk.symbols	31 Jan 2006 16:57:12 -0000	1.84
+++ gtk/gtk.symbols	3 Feb 2006 14:56:37 -0000
@@ -597,6 +597,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
@@ -607,9 +608,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
@@ -2597,6 +2600,19 @@ gtk_rc_style_unref
 #endif
 #endif
 
+#if IN_HEADER(__GTK_RICH_TEXT_H__)
+#if IN_FILE(__GTK_RICH_TEXT_C__)
+gtk_rich_text_deserialize
+gtk_rich_text_get_deserialize_formats
+gtk_rich_text_get_serialize_formats
+gtk_rich_text_register_deserialize_format
+gtk_rich_text_register_serialize_format
+gtk_rich_text_serialize
+gtk_rich_text_unregister_deserialize_format
+gtk_rich_text_unregister_serialize_format
+#endif
+#endif
+
 #if IN_HEADER(__GTK_RULER_H__)
 #if IN_FILE(__GTK_RULER_C__)
 gtk_ruler_draw_pos
@@ -2668,9 +2684,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
@@ -2678,14 +2696,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
 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
 
@@ -2906,6 +2928,7 @@ gtk_text_thaw
 
 #if IN_HEADER(__GTK_TEXT_BUFFER_H__)
 #if IN_FILE(__GTK_TEXT_BUFFER_C__)
+gtk_text_buffer_add_rich_text_tagset
 gtk_text_buffer_add_selection_clipboard
 gtk_text_buffer_apply_tag
 gtk_text_buffer_apply_tag_by_name
@@ -2923,7 +2946,9 @@ 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_receive_rich_text
 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
@@ -2936,6 +2961,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_paste_target_list
+gtk_text_buffer_get_rich_text_tagsets
 gtk_text_buffer_get_selection_bound
 gtk_text_buffer_get_selection_bounds
 gtk_text_buffer_get_slice
@@ -2959,11 +2986,14 @@ gtk_text_buffer_new
 gtk_text_buffer_paste_clipboard
 gtk_text_buffer_place_cursor
 gtk_text_buffer_remove_all_tags
+gtk_text_buffer_remove_rich_text_tagset
 gtk_text_buffer_remove_selection_clipboard
 gtk_text_buffer_remove_tag
 gtk_text_buffer_remove_tag_by_name
 gtk_text_buffer_select_range
+gtk_text_buffer_set_can_receive_rich_text
 gtk_text_buffer_set_modified
+gtk_text_buffer_set_rich_text_tagsets
 gtk_text_buffer_set_text
 #endif
 #endif
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	3 Feb 2006 14:56:37 -0000
@@ -27,6 +27,7 @@
 #include "gtkinvisible.h"
 #include "gtkmain.h"
 #include "gtkmarshalers.h"
+#include "gtkrichtext.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,105 @@ 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
+ * @tagset_names: a list of names of tagsets a #GtkTextBuffer supports
+ * @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,
+                                 GList                           *tagset_names,
+                                 GtkClipboardRichTextReceivedFunc callback,
+                                 gpointer                         user_data)
+{
+  RequestRichTextInfo *info;
+
+  g_return_if_fail (clipboard != NULL);
+  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;
+
+  if (tagset_names)
+    {
+      GList *list;
+
+      for (list = tagset_names; list; list = g_list_next (list))
+        {
+          GdkAtom *atoms;
+          gint     n_atoms;
+
+          atoms = gtk_rich_text_get_deserialize_formats (list->data, &n_atoms);
+
+          if (n_atoms > 0)
+            {
+              info->n_atoms += n_atoms;
+              info->atoms = g_renew (GdkAtom, info->atoms, info->n_atoms);
+
+              memcpy (info->atoms[info->n_atoms - n_atoms], atoms,
+                      n_atoms * sizeof (GdkAtom));
+            }
+
+          g_free (atoms);
+        }
+    }
+  else
+    {
+      info->atoms = gtk_rich_text_get_deserialize_formats (NULL, &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 +1253,8 @@ typedef struct
 {
   GMainLoop *loop;
   gpointer data;
+  GdkAtom format; /* used by rich text */
+  gsize length; /* used by rich text */
 } WaitResults;
 
 static void 
@@ -1254,6 +1366,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
+ * @tagset_names: a list of names of tagsets a #GtkTextBuffer supports
+ * @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,
+                                  GList        *tagset_names,
+                                  GdkAtom      *format,
+                                  gsize        *length)
+{
+  WaitResults results;
+
+  g_return_val_if_fail (clipboard != NULL, 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,
+                                   tagset_names,
+                                   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,
@@ -1356,6 +1537,59 @@ gtk_clipboard_wait_is_text_available (Gt
     {
       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
+ * @tagset_names: a list of names of tagsets a #GtkTextBuffer supports
+ *
+ * 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,
+                                           GList        *tagset_names)
+{
+  GtkSelectionData *data;
+  gboolean result = FALSE;
+
+  data = gtk_clipboard_wait_for_contents (clipboard, gdk_atom_intern_static_string ("TARGETS"));
+  if (data)
+    {
+      if (tagset_names)
+        {
+          GList *list;
+
+          for (list = tagset_names; list; list = g_list_next (list))
+            {
+              result = gtk_selection_data_targets_include_rich_text (data,
+                                                                     list->data);
+              gtk_selection_data_free (data);
+
+              if (result)
+                break;
+            }
+        }
+      else
+        {
+          result = gtk_selection_data_targets_include_rich_text (data, NULL);
+          gtk_selection_data_free (data);
+        }
     }
 
   return result;
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	3 Feb 2006 14:56:38 -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,
+                                      GList                            *tagset_names,
+                                      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,
+                                                    GList         *tagset_names,
+                                                    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,
+                                                    GList        *tagset_names);
+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	3 Feb 2006 14:56:38 -0000
@@ -57,6 +57,7 @@
 #include "gdk.h"
 
 #include "gtkmain.h"
+#include "gtkrichtext.h"
 #include "gtkselection.h"
 #include "gtkintl.h"
 #include "gdk-pixbuf/gdk-pixbuf.h"
@@ -214,12 +215,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;
 }
 
 /**
@@ -339,6 +342,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.
+ * @tagset_name: the name of a set of tags the source/dest #GtkTextBuffer
+ *               supports.
+ *
+ * Appends the rich text targets registered with
+ * gtk_rich_text_register_serialize_format() or
+ * gtk_rich_text_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,
+                                       const gchar    *tagset_name)
+{
+  GdkAtom *atoms;
+  gint     n_atoms;
+  gint     i;
+
+  g_return_if_fail (list != NULL);
+
+  if (deserializable)
+    atoms = gtk_rich_text_get_deserialize_formats (tagset_name, &n_atoms);
+  else
+    atoms = gtk_rich_text_get_serialize_formats (tagset_name, &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 +557,72 @@ gtk_target_list_find (GtkTargetList *lis
 }
 
 /**
+ * gtk_target_table_new_from_list:
+ * @list: a #GtkTargetList
+ * @ntargets: 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          *ntargets)
+{
+  GtkTargetEntry *targets;
+  GList          *tmp_list;
+  gint            i;
+
+  g_return_val_if_fail (list != NULL, NULL);
+  g_return_val_if_fail (ntargets != NULL, NULL);
+
+  *ntargets = g_list_length (list->list);
+  targets = g_new0 (GtkTargetEntry, *ntargets);
+
+  for (i = 0, tmp_list = list->list;
+       i < *ntargets;
+       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
+ * @ntargets: 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            ntargets)
+{
+  gint i;
+
+  g_return_if_fail (targets == NULL || ntargets > 0);
+
+  for (i = 0; i < ntargets; 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 +1716,52 @@ 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
+ * @tagset_name: the name of a set of tags a #GtkTextBuffer supports
+ *
+ * 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,
+                               const gchar *tagset_name)
+{
+  GdkAtom *rich_targets;
+  gint n_rich_targets;
+  gint i, j;
+  gboolean result = FALSE;
+
+  rich_targets = gtk_rich_text_get_deserialize_formats (tagset_name,
+                                                        &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 +1792,40 @@ gtk_selection_data_targets_include_text 
 }
 
 /**
+ * gtk_selection_data_targets_include_rich_text:
+ * @selection_data: a #GtkSelectionData object
+ * @tagset_name: the name of a set of tags a #GtkTextBuffer supports
+ *
+ * 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,
+                                              const gchar      *tagset_name)
+{
+  GdkAtom *targets;
+  gint n_targets;
+  gboolean result = FALSE;
+
+  init_atoms ();
+
+  if (gtk_selection_data_get_targets (selection_data, &targets, &n_targets))
+    {
+      result = gtk_targets_include_rich_text (targets, n_targets, tagset_name);
+      g_free (targets);
+    }
+
+  return result;
+}
+
+/**
  * gtk_targets_include_image:
  * @targets: an array of #GdkAtom<!-- -->s
  * @n_targets: the length of @targets
@@ -2752,6 +2939,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	3 Feb 2006 14:56:39 -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,19 +88,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,
+                                                      const gchar    *tagset_name);
+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 +114,11 @@ gboolean       gtk_target_list_find     
 					  GdkAtom         target,
 					  guint          *info);
 
+GtkTargetEntry * gtk_target_table_new_from_list (GtkTargetList  *list,
+                                                 gint           *ntargets);
+void             gtk_target_table_free          (GtkTargetEntry *targets,
+                                                 gint            ntargets);
+
 /* Public interface */
 
 gboolean gtk_selection_owner_set             (GtkWidget  *widget,
@@ -153,16 +163,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,
+                                                       const gchar      *tagset_name);
 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,
+                                                  const gchar *tagset_name);
+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 +201,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	3 Feb 2006 14:56:42 -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,24 +25,44 @@
  * 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 "gtktextbtree.h"
 #include "gtktextiterprivate.h"
 #include "gtkprivate.h"
+#include "gtkrichtext.h"
 #include "gtkintl.h"
 #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;
+  GtkTargetList  *paste_target_list;
+
+  GtkTargetEntry *copy_target_entries;
+  gint            n_copy_target_entries;
+
+  GtkTargetEntry *paste_target_entries;
+  gint            n_paste_target_entries;
+
+  gboolean        can_receive_rich_text;
+  GList          *rich_text_tagsets;
+};
+
+
 typedef struct _ClipboardRequest ClipboardRequest;
 
 struct _ClipboardRequest
@@ -74,18 +95,14 @@ 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,
+  PROP_CAN_RECEIVE_RICH_TEXT,
+  PROP_RICH_TEXT_TAGSETS
 };
 
 static void gtk_text_buffer_init       (GtkTextBuffer      *tkxt_buffer);
@@ -127,6 +144,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 };
 
@@ -227,7 +246,69 @@ 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));
+
+  /**
+   * GtkTextBuffer:can-receive-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_RECEIVE_RICH_TEXT,
+                                   g_param_spec_boolean ("can-receive-rich-text",
+                                                         P_("Can receive rich text"),
+                                                         P_("Whether it should be possible to paste or drop rich text to the buffer"),
+                                                         FALSE,
+                                                         GTK_PARAM_READWRITE));
+
+  /**
+   * GtkTextBuffer:rich-text-tagsets:
+   *
+   * List of names of collections of tags the text buffer supports for rich
+   * text transfer.
+   *
+   * Since: 2.10
+   */
+  g_object_class_install_property (object_class,
+                                   PROP_RICH_TEXT_TAGSETS,
+                                   g_param_spec_pointer ("rich-text-tagsets",
+                                                         P_("Rich text tagsets"),
+                                                         P_("List of names of collections of tags the text buffer supports for rich text transfer"),
+                                                         GTK_PARAM_READWRITE));
 
   signals[INSERT_TEXT] =
     g_signal_new (I_("insert_text"),
@@ -378,7 +459,13 @@ gtk_text_buffer_class_init (GtkTextBuffe
                   NULL, NULL,
                   _gtk_marshal_VOID__VOID,
                   G_TYPE_NONE,
-                  0);  
+                  0);
+
+  /*  register the internal rich text format for both copy and paste  */
+  gtk_rich_text_register_serialize_format (NULL, NULL, NULL, NULL, NULL);
+  gtk_rich_text_register_deserialize_format (NULL, NULL, NULL, NULL, NULL);
+
+  g_type_class_add_private (object_class, sizeof (GtkTextBufferPrivate));
 }
 
 static void
@@ -428,12 +515,22 @@ 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;
 
+    case PROP_CAN_RECEIVE_RICH_TEXT:
+      gtk_text_buffer_set_can_receive_rich_text (text_buffer,
+                                                 g_value_get_boolean (value));
+      break;
+
+    case PROP_RICH_TEXT_TAGSETS:
+      gtk_text_buffer_set_rich_text_tagsets (text_buffer,
+                                             g_value_get_pointer (value));
+      break;
+
     default:
       break;
     }
@@ -454,23 +551,42 @@ 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;
+
+    case PROP_CAN_RECEIVE_RICH_TEXT:
+      g_value_set_boolean (value,
+                           gtk_text_buffer_get_can_receive_rich_text (text_buffer));
+      break;
+
+    case PROP_RICH_TEXT_TAGSETS:
+      g_value_set_pointer (value,
+                           gtk_text_buffer_get_rich_text_tagsets (text_buffer));
+      break;
+
     default:
       break;
     }
@@ -498,11 +614,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 +639,12 @@ 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_list_foreach (priv->rich_text_tagsets, (GFunc) g_free, NULL);
+  g_free (priv->rich_text_tagsets);
+
   G_OBJECT_CLASS (parent_class)->finalize (object);
 }
 
@@ -2840,22 +2964,35 @@ 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_rich_text_serialize (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);
@@ -2866,12 +3003,19 @@ 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-receive-rich-text", priv->can_receive_rich_text,
+                "rich-text-tagsets",     priv->rich_text_tagsets,
+                NULL);
+
+  g_object_set_data (G_OBJECT (contents), I_("gtk-text-buffer-clipboard"),
+                     GINT_TO_POINTER (1));
+
   return contents;
 }
 
@@ -2882,31 +3026,45 @@ 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)
+    {
+      GtkTextIter start, end;
+      guint8 *str;
+      gsize   len;
+
+      gtk_text_buffer_get_bounds (contents, &start, &end);
+
+      str = gtk_rich_text_serialize (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 +3210,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 +3259,60 @@ 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_rich_text_deserialize (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,6 +3358,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); 
 
@@ -3155,7 +3369,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 +3382,28 @@ 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 (priv->can_receive_rich_text &&
+          gtk_clipboard_wait_is_rich_text_available (clipboard,
+                                                     priv->rich_text_tagsets))
+        {
+          /* Request rich text */
+          gtk_clipboard_request_rich_text (clipboard,
+                                           priv->rich_text_tagsets,
+                                           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 +3413,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 +3441,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 +3754,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 +3765,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 +3795,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,
+                                     priv->n_copy_target_entries - 1);
+
       if (delete_region_after)
         {
           if (interactive)
@@ -3697,6 +3936,354 @@ 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;
+  gint                  i;
+
+  g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
+
+  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)
+{
+  GtkTextBufferPrivate *priv = GTK_TEXT_BUFFER_GET_PRIVATE (buffer);
+  GtkTargetList        *target_list;
+  GList                *list;
+  gint                  i;
+
+  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);
+
+  if (deserializable) /* paste/drag */
+    {
+      if (priv->can_receive_rich_text)
+        {
+          if (priv->rich_text_tagsets)
+            {
+              for (list = priv->rich_text_tagsets; list; list = list->next)
+                gtk_target_list_add_rich_text_targets (target_list,
+                                                       GTK_TEXT_BUFFER_TARGET_INFO_RICH_TEXT,
+                                                       deserializable,
+                                                       list->data);
+            }
+          else
+            {
+              gtk_target_list_add_rich_text_targets (target_list,
+                                                     GTK_TEXT_BUFFER_TARGET_INFO_RICH_TEXT,
+                                                     deserializable,
+                                                     NULL);
+            }
+        }
+    }
+  else /* copy/drop */
+    {
+      /* always offer anything we have: arbitrary tags and tagsets */
+
+      gtk_target_list_add_rich_text_targets (target_list,
+                                             GTK_TEXT_BUFFER_TARGET_INFO_RICH_TEXT,
+                                             deserializable,
+                                             NULL);
+
+      for (list = priv->rich_text_tagsets; list; list = list->next)
+        gtk_target_list_add_rich_text_targets (target_list,
+                                               GTK_TEXT_BUFFER_TARGET_INFO_RICH_TEXT,
+                                               deserializable,
+                                               list->data);
+    }
+
+  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.
+ *
+ * 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.
+ *
+ * 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;
+}
+
+/**
+ * gtk_text_buffer_set_can_receive_rich_text:
+ * @buffer: a #GtkTextBuffer
+ * @can_receive_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_receive_rich_text (GtkTextBuffer *buffer,
+                                           gboolean       can_receive_rich_text)
+{
+  GtkTextBufferPrivate *priv;
+
+  g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
+
+  priv = GTK_TEXT_BUFFER_GET_PRIVATE (buffer);
+
+  can_receive_rich_text = (can_receive_rich_text != FALSE);
+
+  if (priv->can_receive_rich_text != can_receive_rich_text)
+    {
+      priv->can_receive_rich_text = can_receive_rich_text;
+
+      gtk_text_buffer_free_target_lists (buffer);
+
+      g_object_freeze_notify (G_OBJECT (buffer));
+      g_object_notify (G_OBJECT (buffer), "copy-target-list");
+      g_object_notify (G_OBJECT (buffer), "paste-target-list");
+      g_object_notify (G_OBJECT (buffer), "can-receive-rich-text");
+      g_object_thaw_notify (G_OBJECT (buffer));
+    }
+}
+
+/**
+ * gtk_text_buffer_get_can_receive_rich_text:
+ * @buffer: a #GtkTextBuffer
+ *
+ * See gtk_text_buffer_set_can_receive_rich_text().
+ *
+ * Return value: whether rich text pasting and dropping is enabled
+ *
+ * Since: 2.10
+ **/
+gboolean
+gtk_text_buffer_get_can_receive_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_receive_rich_text;
+}
+
+/**
+ * gtk_text_buffer_set_rich_text_tagsets:
+ * @buffer: a #GtkTextBuffer
+ * @GList: the list of tagset names
+ *
+ * A rich-text-tagset is a user-defined name of a collection of
+ * tags. Two text buffers can only exchange rich text if they share a
+ * common tagset, or have no format at all.
+ *
+ * Since: 2.10
+ **/
+void
+gtk_text_buffer_set_rich_text_tagsets (GtkTextBuffer *buffer,
+                                       GList         *tagset_names)
+{
+  GtkTextBufferPrivate *priv;
+  GList                *new;
+  GList                *list;
+
+  g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
+
+  priv = GTK_TEXT_BUFFER_GET_PRIVATE (buffer);
+
+  new = g_list_copy (tagset_names);
+  for (list = new; list; list = g_list_next (list))
+    list->data = g_strdup (list->data);
+
+  g_list_foreach (priv->rich_text_tagsets, (GFunc) g_free, NULL);
+  g_list_free (priv->rich_text_tagsets);
+  priv->rich_text_tagsets = new;
+
+  gtk_text_buffer_free_target_lists (buffer);
+
+  g_object_freeze_notify (G_OBJECT (buffer));
+  g_object_notify (G_OBJECT (buffer), "copy-target-list");
+  g_object_notify (G_OBJECT (buffer), "paste-target-list");
+  g_object_notify (G_OBJECT (buffer), "rich-text-tagsets");
+  g_object_thaw_notify (G_OBJECT (buffer));
+}
+
+/**
+ * gtk_text_buffer_get_rich_text_tagsets:
+ * @buffer: a #GtkTextBuffer
+ *
+ * Retrieve the list of rich text tagset names from the text buffer. See
+ * gtk_text_buffer_set_rich_text_tagsets().
+ *
+ * Return value: the list of rich text tagset names.
+ *
+ * Since: 2.10
+ **/
+GList *
+gtk_text_buffer_get_rich_text_tagsets (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_tagsets;
+}
+
+/**
+ * gtk_text_buffer_add_rich_text_tagset:
+ * @buffer: a #GtkTextBuffer
+ * @tagset_name: the name of a set of tags
+ *
+ * Adds %tagset_name to the list of rich text tagsets supported by
+ * this %buffer.
+ *
+ * Since: 2.10
+ **/
+void
+gtk_text_buffer_add_rich_text_tagset (GtkTextBuffer *buffer,
+                                      const gchar   *tagset_name)
+{
+  GtkTextBufferPrivate *priv;
+
+  g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
+  g_return_if_fail (tagset_name != NULL);
+
+  priv = GTK_TEXT_BUFFER_GET_PRIVATE (buffer);
+
+  g_object_freeze_notify (G_OBJECT (buffer));
+
+  gtk_text_buffer_remove_rich_text_tagset (buffer, tagset_name);
+
+  priv->rich_text_tagsets = g_list_append (priv->rich_text_tagsets,
+                                           g_strdup (tagset_name));
+
+  g_object_notify (G_OBJECT (buffer), "copy-target-list");
+  g_object_notify (G_OBJECT (buffer), "paste-target-list");
+  g_object_notify (G_OBJECT (buffer), "rich-text-tagsets");
+
+  g_object_thaw_notify (G_OBJECT (buffer));
+}
+
+/**
+ * gtk_text_buffer_remove_rich_text_tagset:
+ * @buffer: a #GtkTextBuffer
+ * @tagset_name: the name of a set of tags
+ *
+ * Removed %tagset_name from the list of rich text tagsets supported
+ * by this %buffer.
+ *
+ * Since: 2.10
+ **/
+void
+gtk_text_buffer_remove_rich_text_tagset (GtkTextBuffer *buffer,
+                                         const gchar   *tagset_name)
+{
+  GtkTextBufferPrivate *priv;
+  GList                *list;
+
+  g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
+  g_return_if_fail (tagset_name != NULL);
+
+  priv = GTK_TEXT_BUFFER_GET_PRIVATE (buffer);
+
+  for (list = priv->rich_text_tagsets; list; list = g_list_next (list))
+    if (!strcmp (tagset_name, list->data))
+      {
+        g_free (list->data);
+        priv->rich_text_tagsets = g_list_delete_link (priv->rich_text_tagsets,
+                                                      list);
+
+        g_object_freeze_notify (G_OBJECT (buffer));
+        g_object_notify (G_OBJECT (buffer), "copy-target-list");
+        g_object_notify (G_OBJECT (buffer), "paste-target-list");
+        g_object_notify (G_OBJECT (buffer), "rich-text-tagsets");
+        g_object_thaw_notify (G_OBJECT (buffer));
+
+        break;
+      }
 }
 
 /*
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	3 Feb 2006 14:56:42 -0000
@@ -41,6 +41,13 @@ G_BEGIN_DECLS
  * GtkTextBTree is the PRIVATE internal representation of it.
  */
 
+typedef enum
+{
+  GTK_TEXT_BUFFER_TARGET_INFO_TEXT,
+  GTK_TEXT_BUFFER_TARGET_INFO_RICH_TEXT,
+  GTK_TEXT_BUFFER_TARGET_INFO_BUFFER_CONTENTS
+} GtkTextBufferSelectionInfo;
+
 typedef struct _GtkTextBTree GtkTextBTree;
 
 typedef struct _GtkTextLogAttrCache GtkTextLogAttrCache;
@@ -366,6 +373,22 @@ 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);
+
+void          gtk_text_buffer_set_can_receive_rich_text (GtkTextBuffer *buffer,
+							 gboolean       can_receive_rich_text);
+gboolean      gtk_text_buffer_get_can_receive_rich_text (GtkTextBuffer *buffer);
+
+void          gtk_text_buffer_set_rich_text_tagsets     (GtkTextBuffer *buffer,
+                                                         GList         *tagset_names);
+GList       * gtk_text_buffer_get_rich_text_tagsets     (GtkTextBuffer *buffer);
+
+void          gtk_text_buffer_add_rich_text_tagset      (GtkTextBuffer *buffer,
+                                                         const gchar   *tagset_name);
+void          gtk_text_buffer_remove_rich_text_tagset   (GtkTextBuffer *buffer,
+                                                         const gchar   *tagset_name);
 
 /* 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.304
diff -u -p -r1.304 gtktextview.c
--- gtk/gtktextview.c	21 Jan 2006 04:03:28 -0000	1.304
+++ gtk/gtktextview.c	3 Feb 2006 14:56:42 -0000
@@ -39,6 +39,7 @@
 #include "gtkseparatormenuitem.h"
 #include "gtksettings.h"
 #include "gtkstock.h"
+#include "gtkrichtext.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))
 	{
@@ -6038,23 +6044,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 +6079,48 @@ 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;
 
-      str = NULL;
+      if (gtk_text_buffer_get_selection_bounds (buffer, &start, &end))
+        {
+          /* Extract the selected text */
+          str = gtk_rich_text_serialize (buffer, selection_data->target,
+                                         &start, &end,
+                                         &len);
+        }
+
+      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 +6199,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,19 +6304,47 @@ 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);
     }
 }
 
+static GdkAtom
+find_rich_text_target (GdkDragContext *context,
+                       const gchar    *tagset_name)
+{
+  GdkAtom *atoms;
+  gint     n_atoms;
+  GList   *list;
+  GdkAtom  target = GDK_NONE;
+
+  atoms = gtk_rich_text_get_deserialize_formats (tagset_name, &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);
+
+  return target;
+}
+
 static void
 gtk_text_view_drag_data_received (GtkWidget        *widget,
                                   GdkDragContext   *context,
@@ -6329,7 +6377,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 +6395,42 @@ 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;
+        {
+          copy_tags = FALSE;
+
+          /*  try to find a suitable rich text target instead  */
+          if (gtk_text_buffer_get_can_receive_rich_text (buffer))
+            {
+              GList   *tagsets;
+              GdkAtom  target = GDK_NONE;
+
+              tagsets = gtk_text_buffer_get_rich_text_tagsets (buffer);
+
+              if (tagsets)
+                {
+                  GList *list;
+
+                  for (list = tagsets; list; list = g_list_next (list))
+                    {
+                      target = find_rich_text_target (context, list->data);
+
+                      if (target != GDK_NONE)
+                        break;
+                    }
+                }
+              else
+                {
+                  target = find_rich_text_target (context, NULL);
+                }
+
+              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 +6454,27 @@ 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_rich_text_deserialize (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 +6924,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
