Index: gtk/Makefile.am
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/Makefile.am,v
retrieving revision 1.288
diff -u -p -r1.288 Makefile.am
--- gtk/Makefile.am	22 Nov 2005 10:03:32 -0000	1.288
+++ gtk/Makefile.am	15 Dec 2005 14:06:05 -0000
@@ -478,6 +478,8 @@ gtk_c_sources =                 \
 	gtktext.c		\
 	gtktextbtree.c		\
 	gtktextbuffer.c		\
+	gtktextbufferserialize.c\
+	gtktextbufferserialize.h\
 	gtktextchild.c		\
 	gtktextdisplay.c	\
 	gtktextiter.c		\
Index: gtk/gtk.symbols
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtk.symbols,v
retrieving revision 1.74
diff -u -p -r1.74 gtk.symbols
--- gtk/gtk.symbols	23 Nov 2005 18:06:56 -0000	1.74
+++ gtk/gtk.symbols	15 Dec 2005 14:06:06 -0000
@@ -2880,6 +2880,7 @@ gtk_text_buffer_delete_mark_by_name
 gtk_text_buffer_delete_selection
 gtk_text_buffer_end_user_action
 gtk_text_buffer_get_bounds
+gtk_text_buffer_get_can_paste_rich_text
 gtk_text_buffer_get_char_count
 gtk_text_buffer_get_end_iter
 gtk_text_buffer_get_has_selection
@@ -2893,6 +2894,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_rich_text_format
 gtk_text_buffer_get_selection_bound
 gtk_text_buffer_get_selection_bounds
 gtk_text_buffer_get_slice
@@ -2920,7 +2922,9 @@ gtk_text_buffer_remove_selection_clipboa
 gtk_text_buffer_remove_tag
 gtk_text_buffer_remove_tag_by_name
 gtk_text_buffer_select_range
+gtk_text_buffer_set_can_paste_rich_text
 gtk_text_buffer_set_modified
+gtk_text_buffer_set_rich_text_format
 gtk_text_buffer_set_text
 #endif
 #endif
Index: gtk/gtktextbuffer.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtktextbuffer.c,v
retrieving revision 1.109
diff -u -p -r1.109 gtktextbuffer.c
--- gtk/gtktextbuffer.c	9 Dec 2005 17:26:26 -0000	1.109
+++ gtk/gtktextbuffer.c	15 Dec 2005 14:06:07 -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,16 @@
  * 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 "gtkinvisible.h"
 #include "gtkmarshalers.h"
 #include "gtktextbuffer.h"
+#include "gtktextbufferserialize.h"
 #include "gtktextbtree.h"
 #include "gtktextiterprivate.h"
 #include "gtkprivate.h"
@@ -42,6 +42,17 @@
 #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
+{
+  gboolean  can_paste_rich_text;
+  gchar    *rich_text_format;
+};
+
+
 typedef struct _ClipboardRequest ClipboardRequest;
 
 struct _ClipboardRequest
@@ -74,10 +85,12 @@ enum {
 
   /* Construct */
   PROP_TAG_TABLE,
-  
+
   /* Normal */
   PROP_TEXT,
-  PROP_HAS_SELECTION
+  PROP_HAS_SELECTION,
+  PROP_CAN_PASTE_RICH_TEXT,
+  PROP_RICH_TEXT_FORMAT
 };
 
 enum {
@@ -85,6 +98,8 @@ enum {
   TARGET_TEXT,
   TARGET_COMPOUND_TEXT,
   TARGET_UTF8_STRING,
+  TARGET_TEXT_VIEW_MARKUP,
+  TARGET_TEXT_VIEW_RICH_TEXT_FORMAT,
   TARGET_TEXT_BUFFER_CONTENTS
 };
 
@@ -227,7 +242,37 @@ 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:can-paste-rich-text:
+   *
+   * Whether rich text can be pasted to the buffer.
+   *
+   * Since: 2.10
+   */
+  g_object_class_install_property (object_class,
+                                   PROP_CAN_PASTE_RICH_TEXT,
+                                   g_param_spec_boolean ("can-paste-rich-text",
+                                                         P_("Can paste rich text"),
+                                                         P_("Whether it should be possible to paste rich text to the buffer"),
+                                                         FALSE,
+                                                         GTK_PARAM_READWRITE));
+
+  /**
+   * GtkTextBuffer:rich-text-format:
+   *
+   * Name of a collection of tags that the text view supports.
+   *
+   * Since: 2.10
+   */
+  g_object_class_install_property (object_class,
+                                   PROP_RICH_TEXT_FORMAT,
+                                   g_param_spec_string ("rich-text-format",
+                                                        P_("Rich Text Format"),
+                                                        P_("Name of a collection of tags that the text view supports"),
+                                                        NULL,
+                                                        GTK_PARAM_READWRITE));
 
   signals[INSERT_TEXT] =
     g_signal_new (I_("insert_text"),
@@ -378,7 +423,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
@@ -428,12 +475,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_PASTE_RICH_TEXT:
+      gtk_text_buffer_set_can_paste_rich_text (text_buffer,
+                                               g_value_get_boolean (value));
+      break;
+
+    case PROP_RICH_TEXT_FORMAT:
+      gtk_text_buffer_set_rich_text_format (text_buffer,
+                                            g_value_get_string (value));
+      break;
+
     default:
       break;
     }
@@ -454,23 +511,34 @@ 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_CAN_PASTE_RICH_TEXT:
+      g_value_set_boolean (value,
+                           gtk_text_buffer_get_can_paste_rich_text (text_buffer));
+      break;
+
+    case PROP_RICH_TEXT_FORMAT:
+      g_value_set_string (value,
+                          gtk_text_buffer_get_rich_text_format (text_buffer));
+      break;
+
     default:
       break;
     }
@@ -498,11 +566,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 +591,9 @@ gtk_text_buffer_finalize (GObject *objec
     free_log_attr_cache (buffer->log_attr_cache);
 
   buffer->log_attr_cache = NULL;
-  
+
+  g_free (priv->rich_text_format);
+
   G_OBJECT_CLASS (parent_class)->finalize (object);
 }
 
@@ -2840,8 +2913,7 @@ 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 == TARGET_TEXT_BUFFER_CONTENTS)
         {
           /* Provide the address of the buffer; this will only be
            * used within-process
@@ -2852,6 +2924,32 @@ clipboard_get_selection_cb (GtkClipboard
                                   (void*)&buffer,
                                   sizeof (buffer));
         }
+      else if (info == TARGET_TEXT_VIEW_MARKUP)
+       {
+         gchar *str;
+         gint len;
+
+         str = _gtk_text_buffer_serialize_rich_text (buffer, &start, &end, &len);
+
+         gtk_selection_data_set (selection_data,
+                                 gdk_atom_intern ("application/x-gtk-text-view-markup", FALSE),
+                                 8, /* bytes */
+                                 str, len);
+         g_free (str);
+       }
+      else if (info == TARGET_TEXT_VIEW_RICH_TEXT_FORMAT)
+	{
+	  gint len;
+	  gchar *format;
+	  
+	  format = g_object_get_data (G_OBJECT (buffer), "gtk-text-buffer-clipboard-format");
+	  len = format ? strlen (format) : -1;
+	  
+	  gtk_selection_data_set (selection_data,
+				  gdk_atom_intern ("application/x-gtk-text-view-rich-text-format", FALSE),
+				  8, /* bytes */
+				  format, len);
+	}
       else
         {
           gchar *str;
@@ -2867,11 +2965,19 @@ static GtkTextBuffer *
 create_clipboard_contents_buffer (GtkTextBuffer *buffer)
 {
   GtkTextBuffer *contents;
+  gchar *format;
 
   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));
-  
+  format = GTK_TEXT_BUFFER_GET_PRIVATE (buffer)->rich_text_format;
+
+  g_object_set_data (G_OBJECT (contents), I_("gtk-text-buffer-clipboard"),
+                     GINT_TO_POINTER (1));
+
+  g_object_set_data_full (G_OBJECT (contents),
+                          "gtk-text-buffer-clipboard-format",
+                          g_strdup (format), g_free);
+
   return contents;
 }
 
@@ -2888,8 +2994,7 @@ clipboard_get_contents_cb (GtkClipboard 
   
   g_assert (contents); /* This should never be called unless we own the clipboard */
 
-  if (selection_data->target ==
-      gdk_atom_intern_static_string ("GTK_TEXT_BUFFER_CONTENTS"))
+  if (info == TARGET_TEXT_BUFFER_CONTENTS)
     {
       /* Provide the address of the clipboard buffer; this will only
        * be used within-process. OK to supply a NULL value for contents.
@@ -2900,6 +3005,36 @@ clipboard_get_contents_cb (GtkClipboard 
                               (void*)&contents,
                               sizeof (contents));
     }
+  else if (info == TARGET_TEXT_VIEW_MARKUP)
+    {
+      gchar *str;
+      gint *len;
+      GtkTextIter start, end;
+
+      gtk_text_buffer_get_bounds (contents, &start, &end);
+
+      str = _gtk_text_buffer_serialize_rich_text (contents, &start, &end, &len);
+
+      gtk_selection_data_set (selection_data,
+			      gdk_atom_intern ("application/x-gtk-text-view-markup", FALSE),
+			      8, /* bytes */
+			      str, len);
+      g_free (str);
+    }
+  else if (info == TARGET_TEXT_VIEW_RICH_TEXT_FORMAT)
+    {
+      gint len;
+      gchar *format;
+
+      format = g_object_get_data (G_OBJECT (contents),
+                                  "gtk-text-buffer-clipboard-format");
+      len = format ? strlen (format) : -1;
+
+      gtk_selection_data_set (selection_data,
+                             gdk_atom_intern ("application/x-gtk-text-view-rich-text-format", FALSE),
+                             8, /* bytes */
+                             format, len);
+    }
   else
     {
       gchar *str;
@@ -3100,6 +3235,60 @@ restore_iter (const GtkTextIter *iter,
 #endif
 
 static void
+clipboard_text_view_markup_received (GtkClipboard     *clipboard,
+                                    GtkSelectionData *selection_data,
+                                    gpointer          data)
+{
+  ClipboardRequest *request_data = data;
+  GtkTextIter insert_point;
+  gboolean retval = TRUE;
+  GError *error = NULL;
+  GtkTextBufferPrivate *priv;
+
+  priv = GTK_TEXT_BUFFER_GET_PRIVATE (request_data->buffer);
+
+  /* The length is negative if the request failed. */
+  if (selection_data->length > 0 && selection_data->target ==
+      gdk_atom_intern ("application/x-gtk-text-view-markup", FALSE))
+    {
+      pre_paste_prep (request_data, &insert_point);
+
+      if (request_data->interactive)
+        gtk_text_buffer_begin_user_action (request_data->buffer);
+
+      if (!request_data->interactive ||
+          gtk_text_iter_can_insert (&insert_point,
+                                    request_data->default_editable))
+        retval = _gtk_text_buffer_deserialize_rich_text (request_data->buffer,
+                                                         &insert_point,
+                                                         selection_data->data,
+                                                         selection_data->length,
+                                                         priv->rich_text_format == NULL,
+                                                         &error);
+
+      if (!retval)
+        {
+          g_warning ("error pasting: %s\n", error->message);
+          g_clear_error (&error);
+        }
+
+      if (request_data->interactive)
+        gtk_text_buffer_end_user_action (request_data->buffer);
+
+      if (retval)
+        {
+          post_paste_cleanup (request_data);
+          return;
+        }
+    }
+
+  /* Request the text selection instead */
+  gtk_clipboard_request_text (clipboard,
+                              clipboard_text_received,
+                              data);
+}
+
+static void
 paste_from_buffer (ClipboardRequest    *request_data,
                    GtkTextBuffer       *src_buffer,
                    const GtkTextIter   *start,
@@ -3138,6 +3327,38 @@ paste_from_buffer (ClipboardRequest    *
   free_clipboard_request (request_data);
 }
 
+static gboolean
+formats_match (GtkClipboard *clipboard, const gchar *format)
+{
+  GtkSelectionData *data;
+  gchar *tmp;
+  gboolean retval;
+
+  if (!format)
+    return TRUE;
+
+  data = gtk_clipboard_wait_for_contents (clipboard,
+					  gdk_atom_intern ("application/x-gtk-text-view-rich-text-format", FALSE));
+
+  if (!data)
+    return FALSE;
+
+  if (data->length <= 0)
+    retval = FALSE;
+  else
+    {
+      tmp = g_strndup (data->data, data->length);
+
+      retval = (strcmp (tmp, format) == 0);
+
+      g_free (tmp);
+    }
+
+  gtk_selection_data_free (data);
+
+  return retval;
+}
+      
 static void
 clipboard_clipboard_buffer_received (GtkClipboard     *clipboard,
                                      GtkSelectionData *selection_data,
@@ -3145,6 +3366,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 +3377,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,10 +3390,20 @@ 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_paste_rich_text &&
+          formats_match (clipboard, priv->rich_text_format))
+        /* Request markup */
+        gtk_clipboard_request_contents (clipboard,
+                                        gdk_atom_intern ("application/x-gtk-text-view-markup", FALSE),
+                                        clipboard_text_view_markup_received,
+                                        data);
+      else
+        /* Request the text selection instead */
+        gtk_clipboard_request_text (clipboard,
+                                    clipboard_text_received,
+                                    data);
     }
 }
 
@@ -3180,6 +3412,8 @@ static const GtkTargetEntry targets[] = 
   { "TEXT",   0, TARGET_TEXT },
   { "COMPOUND_TEXT", 0, TARGET_COMPOUND_TEXT },
   { "UTF8_STRING", 0, TARGET_UTF8_STRING },
+  { "application/x-gtk-text-view-markup", 0, TARGET_TEXT_VIEW_MARKUP },
+  { "application/x-gtk-text-view-rich-text-format", 0, TARGET_TEXT_VIEW_RICH_TEXT_FORMAT },
   { "GTK_TEXT_BUFFER_CONTENTS", 0, TARGET_TEXT_BUFFER_CONTENTS }
 };
 
@@ -3697,6 +3931,107 @@ 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);
     }
+}
+
+/**
+ * gtk_text_buffer_set_can_paste_rich_text:
+ * @buffer: a #GtkTextBuffer
+ * @can_paste_rich_text: whether rich text pasting is enabled
+ *
+ * Sets whether rich text can be pasted to the text buffer
+ *
+ * Since: 2.10
+ **/
+void
+gtk_text_buffer_set_can_paste_rich_text (GtkTextBuffer *buffer,
+                                         gboolean       can_paste_rich_text)
+{
+  GtkTextBufferPrivate *priv;
+
+  g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
+
+  priv = GTK_TEXT_BUFFER_GET_PRIVATE (buffer);
+
+  can_paste_rich_text = (can_paste_rich_text != FALSE);
+
+  if (priv->can_paste_rich_text != can_paste_rich_text)
+    {
+      priv->can_paste_rich_text = can_paste_rich_text;
+
+      g_object_notify (G_OBJECT (buffer), "can-paste-rich-text");
+    }
+}
+
+/**
+ * gtk_text_buffer_get_can_paste_rich_text:
+ * @buffer: a #GtkTextBuffer
+ *
+ * See gtk_text_buffer_set_can_paste_rich_text().
+ *
+ * Return value: whether rich text pasting is enabled
+ *
+ * Since: 2.10
+ **/
+gboolean
+gtk_text_buffer_get_can_paste_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_paste_rich_text;
+}
+
+/**
+ * gtk_text_buffer_set_rich_text_format:
+ * @buffer: a #GtkTextBuffer
+ * @format: the rich text format
+ *
+ * The rich-text-format is a user-defined name of a collection of
+ * tags.  Two text buffers can only exchange rich text if they share a
+ * common format, of have no format at all.
+ *
+ * Since: 2.10
+ **/
+void
+gtk_text_buffer_set_rich_text_format (GtkTextBuffer *buffer,
+                                      const gchar   *format)
+{
+  GtkTextBufferPrivate *priv;
+
+  g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
+
+  priv = GTK_TEXT_BUFFER_GET_PRIVATE (buffer);
+
+  g_free (priv->rich_text_format);
+  priv->rich_text_format = g_strdup (format);
+
+  g_object_notify (G_OBJECT (buffer), "rich-text-format");
+}
+
+/**
+ * gtk_text_buffer_get_rich_text_format:
+ * @buffer: a #GtkTextBuffer
+ *
+ * Retrieve the rich text format from the text buffer. See
+ * gtk_text_buffer_set_rich_text_format().
+ *
+ * Return value: the rich text format.
+ *
+ * Since: 2.10
+ **/
+G_CONST_RETURN gchar *
+gtk_text_buffer_get_rich_text_format (GtkTextBuffer *buffer)
+{
+  GtkTextBufferPrivate *priv;
+
+  g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
+
+  priv = GTK_TEXT_BUFFER_GET_PRIVATE (buffer);
+
+  return priv->rich_text_format;
 }
 
 /*
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	15 Dec 2005 14:06:07 -0000
@@ -367,6 +367,14 @@ gboolean        gtk_text_buffer_delete_s
 void            gtk_text_buffer_begin_user_action       (GtkTextBuffer *buffer);
 void            gtk_text_buffer_end_user_action         (GtkTextBuffer *buffer);
 
+void            gtk_text_buffer_set_can_paste_rich_text (GtkTextBuffer *buffer,
+							 gboolean       can_paste_rich_text);
+gboolean        gtk_text_buffer_get_can_paste_rich_text (GtkTextBuffer *buffer);
+
+void                  gtk_text_buffer_set_rich_text_format (GtkTextBuffer *buffer,
+							    const gchar   *format);
+G_CONST_RETURN gchar *gtk_text_buffer_get_rich_text_format (GtkTextBuffer *buffer);
+
 /* INTERNAL private stuff */
 void            _gtk_text_buffer_spew                  (GtkTextBuffer      *buffer);
 
