--- gtk+-2.6.4/gtk/gtktextbuffer.c	2004-11-01 21:57:13.000000000 +0200
+++ gtk+-2.6.4/gtk/gtktextbuffer.c	2005-04-06 16:19:38.023757872 +0300
@@ -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
@@ -39,6 +40,17 @@
 #include "gtktextbtree.h"
 #include "gtktextiterprivate.h"
 #include "gtkintl.h"
+#include "gtktextbufferserialize.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;
 
@@ -71,7 +83,10 @@
   PROP_0,
 
   /* Construct */
-  PROP_TAG_TABLE
+  PROP_TAG_TABLE,
+
+  PROP_CAN_PASTE_RICH_TEXT,
+  PROP_RICH_TEXT_FORMAT  
 };
 
 enum {
@@ -79,6 +94,8 @@
   TARGET_TEXT,
   TARGET_COMPOUND_TEXT,
   TARGET_UTF8_STRING,
+  TARGET_TEXT_VIEW_MARKUP,
+  TARGET_TEXT_VIEW_RICH_TEXT_FORMAT,
   TARGET_TEXT_BUFFER_CONTENTS
 };
 
@@ -185,7 +202,20 @@
                                                         P_("Text Tag Table"),
                                                         GTK_TYPE_TEXT_TAG_TABLE,
                                                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+  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, G_PARAM_READWRITE));
+  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, G_PARAM_READWRITE));
 
+  
   signals[INSERT_TEXT] =
     g_signal_new ("insert_text",
                   G_OBJECT_CLASS_TYPE (object_class),
@@ -335,7 +365,9 @@
                   NULL, NULL,
                   _gtk_marshal_VOID__VOID,
                   G_TYPE_NONE,
-                  0);  
+                  0);
+  
+  g_type_class_add_private (object_class, sizeof (GtkTextBufferPrivate));
 }
 
 static void
@@ -385,7 +417,12 @@
     case PROP_TAG_TABLE:
       set_table (text_buffer, g_value_get_object (value));
       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;
     }
@@ -406,7 +443,14 @@
     case PROP_TAG_TABLE:
       g_value_set_object (value, get_table (text_buffer));
       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;
     }
@@ -434,11 +478,14 @@
 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);
@@ -456,7 +503,9 @@
     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);
 }
 
@@ -2738,8 +2787,7 @@
 
   if (gtk_text_buffer_get_selection_bounds (buffer, &start, &end))
     {
-      if (selection_data->target ==
-          gdk_atom_intern ("GTK_TEXT_BUFFER_CONTENTS", FALSE))
+      if (info == TARGET_TEXT_BUFFER_CONTENTS)
         {
           /* Provide the address of the buffer; this will only be
            * used within-process
@@ -2750,6 +2798,32 @@
                                   (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;
@@ -2765,10 +2839,16 @@
 create_clipboard_contents_buffer (GtkTextBuffer *buffer)
 {
   GtkTextBuffer *contents;
+  gchar *format;
 
   contents = gtk_text_buffer_new (gtk_text_buffer_get_tag_table (buffer));
 
+  format = GTK_TEXT_BUFFER_GET_PRIVATE (buffer)->rich_text_format;
+
   g_object_set_data (G_OBJECT (contents), "gtk-text-buffer-clipboard", GINT_TO_POINTER (1));
+
+  g_object_set_data_full (G_OBJECT (contents), "gtk-text-buffer-clipboard-format",
+ 			  format ? g_strdup (format) : NULL, g_free);
   
   return contents;
 }
@@ -2786,8 +2866,7 @@
   
   g_assert (contents); /* This should never be called unless we own the clipboard */
 
-  if (selection_data->target ==
-      gdk_atom_intern ("GTK_TEXT_BUFFER_CONTENTS", FALSE))
+  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.
@@ -2798,6 +2877,35 @@
                               (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;
@@ -2992,6 +3100,54 @@
 #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);
+
+  if (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);
+       }
+
+      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,
@@ -3029,6 +3185,35 @@
   g_free (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->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,
@@ -3036,6 +3221,7 @@
 {
   ClipboardRequest *request_data = data;
   GtkTextBuffer *src_buffer;
+  GtkTextBufferPrivate *priv;
   
   src_buffer = selection_data_get_buffer (selection_data, request_data); 
 
@@ -3059,10 +3245,19 @@
     }
   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);
     }
 }
 
@@ -3071,6 +3266,8 @@
   { "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 }
 };
 
@@ -3591,6 +3788,68 @@
     }
 }
 
+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");
+    }
+}
+
+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;
+}
+
+void
+gtk_text_buffer_set_rich_text_format (GtkTextBuffer *buffer,
+                                     const gchar   *format)
+{
+  gchar *new_format;
+  GtkTextBufferPrivate *priv;
+
+  g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
+
+  priv = GTK_TEXT_BUFFER_GET_PRIVATE (buffer);
+
+  new_format = g_strdup (format);
+  g_free (priv->rich_text_format);
+
+  priv->rich_text_format = new_format;
+  g_object_notify (G_OBJECT (buffer), "rich_text_format");
+}
+
+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;
+}
+
 /*
  * Logical attribute cache
  */