Index: gtk/gtklabelprivate.h
===================================================================
--- gtk/gtklabelprivate.h	(revision 0)
+++ gtk/gtklabelprivate.h	(revision 0)
@@ -0,0 +1,80 @@
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
+ */
+ 
+#ifndef __GTK_LABEL_PRIVATE_H__
+#define __GTK_LABEL_PRIVATE_H__
+
+#include <gdk/gdk.h>
+#include <gtk/gtkwidget.h>
+#include <gtk/gtkbindings.h>
+#include <pango/pango.h>
+
+G_BEGIN_DECLS
+ 
+struct _GtkLabelSelectionInfo
+{
+  GdkWindow *window;
+  gint selection_anchor;
+  gint selection_end;
+
+  GtkWidget *popup_menu;
+  GtkWidget *delete_item;
+  GtkWidget *cut_item;
+  GtkWidget *paste_item;
+  guint clipboard_has_text : 1;
+
+  gint drag_start_x;
+  gint drag_start_y;
+
+  guint in_drag : 1;
+};
+
+void _gtk_label_clear_layout           (GtkLabel       *label);
+void _gtk_label_select_region_index    (GtkLabel       *label,
+                                        gint            anchor_index,
+                                        gint            end_index);
+gboolean _gtk_label_delete_text        (GtkLabel       *label,
+                                        gint            start_pos,
+                                        gint            end_pos);
+void _gtk_label_insert_text            (GtkLabel       *label,
+                                        const gchar    *new_text,
+                                        gint           new_text_length,
+                                        gint           *index);
+void _gtk_label_add_move_binding       (GtkBindingSet  *binding_set,
+                                        guint           keyval,
+                                        guint           modmask,
+                                        GtkMovementStep step,
+                                        gint            count);
+void _gtk_label_ensure_layout_internal (GtkLabel       *label,
+                                        gint            preedit_length,
+                                        gchar          *preedit_string,
+                                        PangoAttrList  *preedit_attrs);
+void _gtk_label_set_cursor_visible     (GtkLabel       *label,
+                                        gboolean        visible);
+gboolean _gtk_label_get_cursor_visible (GtkLabel       *label);
+
+G_END_DECLS
+
+#endif /* __GTK_LABEL_PRIVATE_H__ */
Index: gtk/gtk.h
===================================================================
--- gtk/gtk.h	(revision 21324)
+++ gtk/gtk.h	(working copy)
@@ -76,6 +76,7 @@
 #include <gtk/gtkdnd.h>
 #include <gtk/gtkdrawingarea.h>
 #include <gtk/gtkeditable.h>
+#include <gtk/gtkeditablelabel.h>
 #include <gtk/gtkentry.h>
 #include <gtk/gtkentrycompletion.h>
 #include <gtk/gtkenums.h>
Index: gtk/Makefile.am
===================================================================
--- gtk/Makefile.am	(revision 21324)
+++ gtk/Makefile.am	(working copy)
@@ -187,6 +187,7 @@ gtk_public_h_sources =          \
 	gtkdnd.h		\
 	gtkdrawingarea.h	\
 	gtkeditable.h           \
+	gtkeditablelabel.h      \
 	gtkentry.h		\
 	gtkentrycompletion.h	\
 	gtkenums.h		\
@@ -356,6 +357,7 @@ gtk_private_h_sources =		\
 	gtkfilesystemmodel.h	\
 	gtkiconcache.h		\
 	gtkintl.h		\
+	gtklabelprivate.h       \
 	gtkkeyhash.h		\
 	gtkmnemonichash.h	\
 	gtkpathbar.h		\
@@ -433,6 +435,7 @@ gtk_base_c_sources =            \
 	gtkdialog.c		\
 	gtkdrawingarea.c	\
 	gtkeditable.c           \
+	gtkeditablelabel.c      \
 	gtkentry.c		\
 	gtkentrycompletion.c	\
 	gtkeventbox.c		\
Index: gtk/gtklabel.c
===================================================================
--- gtk/gtklabel.c	(revision 21324)
+++ gtk/gtklabel.c	(working copy)
@@ -44,6 +44,7 @@
 #include "gtkstock.h"
 #include "gtkbindings.h"
 #include "gtkbuildable.h"
+#include "gtklabelprivate.h"
 #include "gtkprivate.h"
 #include "gtkalias.h"
 
@@ -54,22 +55,13 @@ typedef struct
   gint wrap_width;
   gint width_chars;
   gint max_width_chars;
+  gint n_bytes;
+  gint text_size;
+
+  guint cursor_visible : 1;
 }
 GtkLabelPrivate;
 
-struct _GtkLabelSelectionInfo
-{
-  GdkWindow *window;
-  gint selection_anchor;
-  gint selection_end;
-  GtkWidget *popup_menu;
-  
-  gint drag_start_x;
-  gint drag_start_y;
-
-  guint in_drag : 1;
-};
-
 enum {
   MOVE_CURSOR,
   COPY_CLIPBOARD,
@@ -163,12 +155,8 @@ static void gtk_label_screen_changed    
 
 static void gtk_label_create_window       (GtkLabel *label);
 static void gtk_label_destroy_window      (GtkLabel *label);
-static void gtk_label_clear_layout        (GtkLabel *label);
 static void gtk_label_ensure_layout       (GtkLabel *label);
 static void gtk_label_invalidate_wrap_width (GtkLabel *label);
-static void gtk_label_select_region_index (GtkLabel *label,
-                                           gint      anchor_index,
-                                           gint      end_index);
 
 static gboolean gtk_label_mnemonic_activate (GtkWidget         *widget,
 					     gboolean           group_cycling);
@@ -218,12 +206,12 @@ G_DEFINE_TYPE_WITH_CODE (GtkLabel, gtk_l
 			 G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
 						gtk_label_buildable_interface_init));
 
-static void
-add_move_binding (GtkBindingSet  *binding_set,
-		  guint           keyval,
-		  guint           modmask,
-		  GtkMovementStep step,
-		  gint            count)
+void
+_gtk_label_add_move_binding (GtkBindingSet  *binding_set,
+                             guint           keyval,
+                             guint           modmask,
+                             GtkMovementStep step,
+                             gint            count)
 {
   g_return_if_fail ((modmask & GDK_SHIFT_MASK) == 0);
   
@@ -538,34 +526,34 @@ gtk_label_class_init (GtkLabelClass *cla
   binding_set = gtk_binding_set_by_class (class);
 
   /* Moving the insertion point */
-  add_move_binding (binding_set, GDK_Right, 0,
+  _gtk_label_add_move_binding (binding_set, GDK_Right, 0,
 		    GTK_MOVEMENT_VISUAL_POSITIONS, 1);
   
-  add_move_binding (binding_set, GDK_Left, 0,
+  _gtk_label_add_move_binding (binding_set, GDK_Left, 0,
 		    GTK_MOVEMENT_VISUAL_POSITIONS, -1);
 
-  add_move_binding (binding_set, GDK_KP_Right, 0,
+  _gtk_label_add_move_binding (binding_set, GDK_KP_Right, 0,
 		    GTK_MOVEMENT_VISUAL_POSITIONS, 1);
   
-  add_move_binding (binding_set, GDK_KP_Left, 0,
+  _gtk_label_add_move_binding (binding_set, GDK_KP_Left, 0,
 		    GTK_MOVEMENT_VISUAL_POSITIONS, -1);
   
-  add_move_binding (binding_set, GDK_f, GDK_CONTROL_MASK,
+  _gtk_label_add_move_binding (binding_set, GDK_f, GDK_CONTROL_MASK,
 		    GTK_MOVEMENT_LOGICAL_POSITIONS, 1);
   
-  add_move_binding (binding_set, GDK_b, GDK_CONTROL_MASK,
+  _gtk_label_add_move_binding (binding_set, GDK_b, GDK_CONTROL_MASK,
 		    GTK_MOVEMENT_LOGICAL_POSITIONS, -1);
   
-  add_move_binding (binding_set, GDK_Right, GDK_CONTROL_MASK,
+  _gtk_label_add_move_binding (binding_set, GDK_Right, GDK_CONTROL_MASK,
 		    GTK_MOVEMENT_WORDS, 1);
 
-  add_move_binding (binding_set, GDK_Left, GDK_CONTROL_MASK,
+  _gtk_label_add_move_binding (binding_set, GDK_Left, GDK_CONTROL_MASK,
 		    GTK_MOVEMENT_WORDS, -1);
 
-  add_move_binding (binding_set, GDK_KP_Right, GDK_CONTROL_MASK,
+  _gtk_label_add_move_binding (binding_set, GDK_KP_Right, GDK_CONTROL_MASK,
 		    GTK_MOVEMENT_WORDS, 1);
 
-  add_move_binding (binding_set, GDK_KP_Left, GDK_CONTROL_MASK,
+  _gtk_label_add_move_binding (binding_set, GDK_KP_Left, GDK_CONTROL_MASK,
 		    GTK_MOVEMENT_WORDS, -1);
 
   /* select all */
@@ -606,34 +594,34 @@ gtk_label_class_init (GtkLabelClass *cla
 				G_TYPE_INT, 0,
 				G_TYPE_BOOLEAN, FALSE);
 
-  add_move_binding (binding_set, GDK_f, GDK_MOD1_MASK,
+  _gtk_label_add_move_binding (binding_set, GDK_f, GDK_MOD1_MASK,
 		    GTK_MOVEMENT_WORDS, 1);
 
-  add_move_binding (binding_set, GDK_b, GDK_MOD1_MASK,
+  _gtk_label_add_move_binding (binding_set, GDK_b, GDK_MOD1_MASK,
 		    GTK_MOVEMENT_WORDS, -1);
 
-  add_move_binding (binding_set, GDK_Home, 0,
+  _gtk_label_add_move_binding (binding_set, GDK_Home, 0,
 		    GTK_MOVEMENT_DISPLAY_LINE_ENDS, -1);
 
-  add_move_binding (binding_set, GDK_End, 0,
+  _gtk_label_add_move_binding (binding_set, GDK_End, 0,
 		    GTK_MOVEMENT_DISPLAY_LINE_ENDS, 1);
 
-  add_move_binding (binding_set, GDK_KP_Home, 0,
+  _gtk_label_add_move_binding (binding_set, GDK_KP_Home, 0,
 		    GTK_MOVEMENT_DISPLAY_LINE_ENDS, -1);
 
-  add_move_binding (binding_set, GDK_KP_End, 0,
+  _gtk_label_add_move_binding (binding_set, GDK_KP_End, 0,
 		    GTK_MOVEMENT_DISPLAY_LINE_ENDS, 1);
   
-  add_move_binding (binding_set, GDK_Home, GDK_CONTROL_MASK,
+  _gtk_label_add_move_binding (binding_set, GDK_Home, GDK_CONTROL_MASK,
 		    GTK_MOVEMENT_BUFFER_ENDS, -1);
 
-  add_move_binding (binding_set, GDK_End, GDK_CONTROL_MASK,
+  _gtk_label_add_move_binding (binding_set, GDK_End, GDK_CONTROL_MASK,
 		    GTK_MOVEMENT_BUFFER_ENDS, 1);
 
-  add_move_binding (binding_set, GDK_KP_Home, GDK_CONTROL_MASK,
+  _gtk_label_add_move_binding (binding_set, GDK_KP_Home, GDK_CONTROL_MASK,
 		    GTK_MOVEMENT_BUFFER_ENDS, -1);
 
-  add_move_binding (binding_set, GDK_KP_End, GDK_CONTROL_MASK,
+  _gtk_label_add_move_binding (binding_set, GDK_KP_End, GDK_CONTROL_MASK,
 		    GTK_MOVEMENT_BUFFER_ENDS, 1);
 
   /* copy */
@@ -808,6 +796,8 @@ gtk_label_init (GtkLabel *label)
   priv->width_chars = -1;
   priv->max_width_chars = -1;
   priv->wrap_width = -1;
+  priv->text_size = 1;
+  priv->n_bytes = 0;
   label->label = NULL;
 
   label->jtype = GTK_JUSTIFY_LEFT;
@@ -821,7 +811,7 @@ gtk_label_init (GtkLabel *label)
   
   label->mnemonic_keyval = GDK_VoidSymbol;
   label->layout = NULL;
-  label->text = NULL;
+  label->text = g_malloc (priv->text_size);
   label->attrs = NULL;
 
   label->mnemonic_widget = NULL;
@@ -1484,11 +1474,16 @@ static void
 gtk_label_set_text_internal (GtkLabel *label,
 			     gchar    *str)
 {
-  g_free (label->text);
-  
-  label->text = str;
+  int tmp_pos;
+
+  if (strcmp (label->text, str) == 0)
+    return;
 
-  gtk_label_select_region_index (label, 0, 0);
+  _gtk_label_delete_text (label, 0, -1);
+  tmp_pos = 0;
+  _gtk_label_insert_text (label, str, strlen (str), &tmp_pos);
+
+  _gtk_label_select_region_index (label, 0, 0);
 }
 
 static void
@@ -1586,7 +1581,7 @@ gtk_label_recalculate (GtkLabel *label)
       g_object_notify (G_OBJECT (label), "mnemonic-keyval");
     }
 
-  gtk_label_clear_layout (label);  
+  _gtk_label_clear_layout (label);  
   gtk_widget_queue_resize (GTK_WIDGET (label));
 }
 
@@ -1635,7 +1630,7 @@ gtk_label_set_attributes (GtkLabel      
 
   gtk_label_set_attributes_internal (label, attrs);
   
-  gtk_label_clear_layout (label);  
+  _gtk_label_clear_layout (label);  
   gtk_widget_queue_resize (GTK_WIDGET (label));
 }
 
@@ -1828,6 +1823,8 @@ gtk_label_get_text (GtkLabel *label)
   return label->text;
 }
 
+
+
 static PangoAttrList *
 gtk_label_pattern_to_attrs (GtkLabel      *label,
 			    const gchar   *pattern)
@@ -1910,7 +1907,7 @@ gtk_label_set_pattern (GtkLabel	   *labe
   else
     gtk_label_recalculate (label);
 
-  gtk_label_clear_layout (label);  
+  _gtk_label_clear_layout (label);  
   gtk_widget_queue_resize (GTK_WIDGET (label));
 }
 
@@ -1939,7 +1936,7 @@ gtk_label_set_justify (GtkLabel        *
       label->jtype = jtype;
 
       /* No real need to be this drastic, but easier than duplicating the code */
-      gtk_label_clear_layout (label);
+      _gtk_label_clear_layout (label);
       
       g_object_notify (G_OBJECT (label), "justify");
       gtk_widget_queue_resize (GTK_WIDGET (label));
@@ -1984,7 +1981,7 @@ gtk_label_set_ellipsize (GtkLabel       
       label->ellipsize = mode;
 
       /* No real need to be this drastic, but easier than duplicating the code */
-      gtk_label_clear_layout (label);
+      _gtk_label_clear_layout (label);
       
       g_object_notify (G_OBJECT (label), "ellipsize");
       gtk_widget_queue_resize (GTK_WIDGET (label));
@@ -2131,7 +2128,7 @@ gtk_label_set_line_wrap (GtkLabel *label
     {
       label->wrap = wrap;
 
-      gtk_label_clear_layout (label);
+      _gtk_label_clear_layout (label);
       gtk_widget_queue_resize (GTK_WIDGET (label));
       g_object_notify (G_OBJECT (label), "wrap");
     }
@@ -2241,8 +2238,8 @@ gtk_label_finalize (GObject *object)
   G_OBJECT_CLASS (gtk_label_parent_class)->finalize (object);
 }
 
-static void
-gtk_label_clear_layout (GtkLabel *label)
+void
+_gtk_label_clear_layout (GtkLabel *label)
 {
   if (label->layout)
     {
@@ -2324,8 +2321,11 @@ get_label_wrap_width (GtkLabel *label)
   return priv->wrap_width;
 }
 
-static void
-gtk_label_ensure_layout (GtkLabel *label)
+void
+_gtk_label_ensure_layout_internal (GtkLabel *label,
+                                   gint preedit_length,
+                                   gchar *preedit_string,
+                                   PangoAttrList *preedit_attrs)
 {
   GtkWidget *widget;
   PangoRectangle logical_rect;
@@ -2339,6 +2339,21 @@ gtk_label_ensure_layout (GtkLabel *label
     {
       PangoAlignment align = PANGO_ALIGN_LEFT; /* Quiet gcc */
       gdouble angle = gtk_label_get_angle (label);
+      GtkLabelPrivate *priv = GTK_LABEL_GET_PRIVATE (label);
+      char *text_with_preedit = NULL;
+
+      if (preedit_length != 0 && preedit_string != NULL)
+        {
+          GString *tmp_string = g_string_new (NULL);
+
+          g_string_prepend_len (tmp_string, label->text, priv->n_bytes);
+          g_string_insert (tmp_string, label->select_info->selection_anchor, preedit_string);
+
+          pango_attr_list_splice (label->effective_attrs, preedit_attrs,
+                                  label->select_info->selection_anchor, preedit_length);
+
+          text_with_preedit = g_string_free (tmp_string, FALSE);
+        }
 
       if (angle != 0.0 && !label->wrap && !label->ellipsize && !label->select_info)
 	{
@@ -2362,8 +2377,16 @@ gtk_label_ensure_layout (GtkLabel *label
 	  label->have_transform = FALSE;
 	}
 
-      label->layout = gtk_widget_create_pango_layout (widget, label->text);
-
+      if (text_with_preedit)
+        {
+          label->layout = gtk_widget_create_pango_layout (widget, text_with_preedit);
+          g_free (text_with_preedit);
+        }
+      else
+        {
+          label->layout = gtk_widget_create_pango_layout (widget, label->text);
+        }
+  
       if (label->effective_attrs)
 	pango_layout_set_attributes (label->layout, label->effective_attrs);
       
@@ -2468,6 +2491,12 @@ gtk_label_ensure_layout (GtkLabel *label
 }
 
 static void
+gtk_label_ensure_layout (GtkLabel *label)
+{
+  _gtk_label_ensure_layout_internal (label, 0, NULL, NULL);
+}
+
+static void
 gtk_label_size_request (GtkWidget      *widget,
 			GtkRequisition *requisition)
 {
@@ -2493,7 +2522,7 @@ gtk_label_size_request (GtkWidget      *
    */
 
   if (label->wrap)
-    gtk_label_clear_layout (label);
+    _gtk_label_clear_layout (label);
 
   gtk_label_ensure_layout (label);
 
@@ -2629,7 +2658,7 @@ gtk_label_style_set (GtkWidget *widget,
   GtkLabel *label = GTK_LABEL (widget);
 
   /* We have to clear the layout, fonts etc. may have changed */
-  gtk_label_clear_layout (label);
+  _gtk_label_clear_layout (label);
   gtk_label_invalidate_wrap_width (label);
 }
 
@@ -2900,7 +2929,8 @@ gtk_label_expose (GtkWidget      *widget
           gdk_gc_set_clip_region (widget->style->black_gc, NULL);
           gdk_region_destroy (clip);
         }
-      else if (label->select_info && GTK_WIDGET_HAS_FOCUS (widget))
+      else if (label->select_info && GTK_WIDGET_HAS_FOCUS (widget) &&
+               GTK_LABEL_GET_PRIVATE (label)->cursor_visible)
 	gtk_label_draw_cursor (label, x, y);
     }
 
@@ -3212,7 +3242,7 @@ gtk_label_select_word (GtkLabel *label)
   min = MIN (min, start_index);
   max = MAX (max, end_index);
 
-  gtk_label_select_region_index (label, min, max);
+  _gtk_label_select_region_index (label, min, max);
 }
 
 static void
@@ -3262,7 +3292,7 @@ gtk_label_button_press (GtkWidget      *
 
       if (event->type == GDK_3BUTTON_PRESS)
 	{
-	  gtk_label_select_region_index (label, 0, strlen (label->text));
+	  _gtk_label_select_region_index (label, 0, strlen (label->text));
 	  return TRUE;
 	}
       
@@ -3295,12 +3325,12 @@ gtk_label_button_press (GtkWidget      *
 	      max = tmp;
 	    }
 	  
-	  gtk_label_select_region_index (label, min, max);
+	  _gtk_label_select_region_index (label, min, max);
 	}
       else 
 	{
 	  if (event->type == GDK_3BUTTON_PRESS)
-	    gtk_label_select_region_index (label, 0, strlen (label->text));
+	    _gtk_label_select_region_index (label, 0, strlen (label->text));
 	  else if (event->type == GDK_2BUTTON_PRESS)
 	    gtk_label_select_word (label);
 	  else if (min < max && min <= index && index <= max)
@@ -3311,7 +3341,7 @@ gtk_label_button_press (GtkWidget      *
 	    }
 	  else
 	    /* start a replacement */
-	    gtk_label_select_region_index (label, index, index);
+	    _gtk_label_select_region_index (label, index, index);
 	}
   
       return TRUE;
@@ -3342,7 +3372,7 @@ gtk_label_button_release (GtkWidget     
       label->select_info->in_drag = 0;
 
       get_layout_index (label, event->x, event->y, &index);
-      gtk_label_select_region_index (label, index, index);
+      _gtk_label_select_region_index (label, index, index);
       
       return FALSE;
     }
@@ -3453,7 +3483,7 @@ gtk_label_motion (GtkWidget      *widget
     {
       get_layout_index (label, x, y, &index);
       
-      gtk_label_select_region_index (label,
+      _gtk_label_select_region_index (label,
 				     label->select_info->selection_anchor,
 				     index);
     }
@@ -3645,7 +3675,7 @@ gtk_label_set_angle (GtkLabel *label,
     {
       *label_angle = angle;
       
-      gtk_label_clear_layout (label);
+      _gtk_label_clear_layout (label);
       gtk_widget_queue_resize (GTK_WIDGET (label));
 
       g_object_notify (G_OBJECT (label), "angle");
@@ -3743,8 +3773,8 @@ clear_text_callback (GtkClipboard     *c
     }
 }
 
-static void
-gtk_label_select_region_index (GtkLabel *label,
+void
+_gtk_label_select_region_index (GtkLabel *label,
                                gint      anchor_index,
                                gint      end_index)
 {
@@ -3824,7 +3854,7 @@ gtk_label_select_region  (GtkLabel *labe
       if (end_offset < 0)
         end_offset = g_utf8_strlen (label->text, -1);
       
-      gtk_label_select_region_index (label,
+      _gtk_label_select_region_index (label,
                                      g_utf8_offset_to_pointer (label->text, start_offset) - label->text,
                                      g_utf8_offset_to_pointer (label->text, end_offset) - label->text);
     }
@@ -4041,7 +4071,7 @@ gtk_label_set_single_line_mode (GtkLabel
     {
       label->single_line_mode = single_line_mode;
 
-      gtk_label_clear_layout (label);
+      _gtk_label_clear_layout (label);
       gtk_widget_queue_resize (GTK_WIDGET (label));
 
       g_object_notify (G_OBJECT (label), "single-line-mode");
@@ -4389,11 +4419,11 @@ gtk_label_move_cursor (GtkLabel       *l
     }
 
   if (extend_selection)
-    gtk_label_select_region_index (label,
+    _gtk_label_select_region_index (label,
 				   label->select_info->selection_anchor,
 				   new_pos);
   else
-    gtk_label_select_region_index (label, new_pos, new_pos);
+    _gtk_label_select_region_index (label, new_pos, new_pos);
 }
 
 static void
@@ -4427,7 +4457,7 @@ gtk_label_copy_clipboard (GtkLabel *labe
 static void
 gtk_label_select_all (GtkLabel *label)
 {
-  gtk_label_select_region_index (label, 0, strlen (label->text));
+  _gtk_label_select_region_index (label, 0, strlen (label->text));
 }
 
 /* Quick hack of a popup menu
@@ -4440,7 +4470,7 @@ activate_cb (GtkWidget *menuitem,
   g_signal_emit_by_name (label, signal);
 }
 
-static void
+static GtkWidget *
 append_action_signal (GtkLabel     *label,
 		      GtkWidget    *menu,
 		      const gchar  *stock_id,
@@ -4454,9 +4484,11 @@ append_action_signal (GtkLabel     *labe
 		    G_CALLBACK (activate_cb), label);
 
   gtk_widget_set_sensitive (menuitem, sensitive);
-  
+
   gtk_widget_show (menuitem);
   gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
+
+  return menuitem;
 }
 
 static void
@@ -4502,20 +4534,30 @@ popup_position_func (GtkMenu   *menu,
   *y = CLAMP (*y, 0, MAX (0, gdk_screen_get_height (screen) - req.height));
 }
 
+typedef struct
+{
+  GtkLabel *label;
+  gint button;
+  guint time;
+  gboolean event;
+} PopupInfo;
 
 static void
-gtk_label_do_popup (GtkLabel       *label,
-                    GdkEventButton *event)
+popup_targets_received (GtkClipboard *clipoard,
+                        GtkSelectionData *data,
+                        gpointer user_data)
 {
+  PopupInfo *info = user_data;
+  GtkLabel *label = info->label;
   GtkWidget *menuitem;
   gboolean have_selection;
 
   if (label->select_info == NULL)
     return;
-    
+
   if (label->select_info->popup_menu)
     gtk_widget_destroy (label->select_info->popup_menu);
-  
+
   label->select_info->popup_menu = gtk_menu_new ();
 
   gtk_menu_attach_to_widget (GTK_MENU (label->select_info->popup_menu),
@@ -4524,24 +4566,25 @@ gtk_label_do_popup (GtkLabel       *labe
 
   have_selection =
     label->select_info->selection_anchor != label->select_info->selection_end;
+  label->select_info->clipboard_has_text = gtk_selection_data_targets_include_text (data);
 
+  label->select_info->cut_item = append_action_signal (label, label->select_info->popup_menu,
+                                                       GTK_STOCK_CUT, "cut-clipboard", FALSE);  
+  append_action_signal (label, label->select_info->popup_menu,
+                        GTK_STOCK_COPY, "copy-clipboard", have_selection);
+  label->select_info->paste_item = append_action_signal (label, label->select_info->popup_menu,
+                                                         GTK_STOCK_PASTE, "paste-clipboard", FALSE);
 
-  append_action_signal (label, label->select_info->popup_menu, GTK_STOCK_CUT, "cut-clipboard",
-                        FALSE);
-  append_action_signal (label, label->select_info->popup_menu, GTK_STOCK_COPY, "copy-clipboard",
-                        have_selection);
-  append_action_signal (label, label->select_info->popup_menu, GTK_STOCK_PASTE, "paste-clipboard",
-                        FALSE);
-  
   menuitem = gtk_image_menu_item_new_from_stock (GTK_STOCK_DELETE, NULL);
   gtk_widget_set_sensitive (menuitem, FALSE);
   gtk_widget_show (menuitem);
   gtk_menu_shell_append (GTK_MENU_SHELL (label->select_info->popup_menu), menuitem);
+  label->select_info->delete_item = menuitem;
 
   menuitem = gtk_separator_menu_item_new ();
   gtk_widget_show (menuitem);
   gtk_menu_shell_append (GTK_MENU_SHELL (label->select_info->popup_menu), menuitem);
-      
+
   menuitem = gtk_image_menu_item_new_from_stock (GTK_STOCK_SELECT_ALL, NULL);
   g_signal_connect_swapped (menuitem, "activate",
 			    G_CALLBACK (gtk_label_select_all), label);
@@ -4552,16 +4595,171 @@ gtk_label_do_popup (GtkLabel       *labe
 		 signals[POPULATE_POPUP],
 		 0,
 		 label->select_info->popup_menu);
-  
-  if (event)
+
+  if (info->event)
     gtk_menu_popup (GTK_MENU (label->select_info->popup_menu), NULL, NULL,
                     NULL, NULL,
-                    event->button, event->time);
+                    info->button, info->time);
   else
     gtk_menu_popup (GTK_MENU (label->select_info->popup_menu), NULL, NULL,
                     popup_position_func, label,
-                    0, gtk_get_current_event_time ());
+                    info->button, info->time);
+
+  g_object_unref (label);
+  g_slice_free (PopupInfo, info);
+}
+
+static void
+gtk_label_do_popup (GtkLabel       *label,
+                    GdkEventButton *event)
+{
+  PopupInfo *info = g_slice_new (PopupInfo);
+
+  /* In order to know what entries we should make sensitive, we
+   * ask for the current targets of the clipboard, and when
+   * we get them, then we actually pop up the menu.
+   */
+  info->label = g_object_ref (label);
+  
+  if (event)
+    {
+      info->button = event->button;
+      info->time = event->time;
+      info->event = TRUE;
+    }
+  else
+    {
+      info->button = 0;
+      info->time = gtk_get_current_event_time ();
+      info->event = FALSE;
+    }
+
+  gtk_clipboard_request_contents (gtk_widget_get_clipboard (GTK_WIDGET (label), GDK_SELECTION_CLIPBOARD),
+				  gdk_atom_intern_static_string ("TARGETS"),
+				  popup_targets_received,
+				  info);
+}
+
+void
+_gtk_label_insert_text (GtkLabel *label,
+                        const gchar *new_text,
+                        gint         new_text_length,
+                        gint        *index)
+{
+  GtkLabelPrivate *priv = GTK_LABEL_GET_PRIVATE (label);
+
+  if (new_text_length + priv->n_bytes + 1 > priv->text_size)
+    {
+      while (new_text_length + priv->n_bytes + 1 > priv->text_size)
+        {
+          if (priv->text_size == 0)
+            priv->text_size = 16;
+          else
+            priv->text_size *= 2;
+        }
+
+      label->text = g_realloc (label->text, priv->text_size);
+    }
+
+  g_object_freeze_notify (G_OBJECT (label));
+
+  g_memmove (label->text + *index + new_text_length,
+             label->text + *index, priv->n_bytes - *index);
+  memcpy (label->text + *index, new_text, new_text_length);
+
+  priv->n_bytes += new_text_length;
+
+  /* NUL terminate for safety and convenience */
+  label->text[priv->n_bytes] = '\0';
+
+  g_object_notify (G_OBJECT (label), "label");
+
+  if (label->select_info)
+    {
+      if (label->select_info->selection_anchor > *index)
+        {
+          g_object_notify (G_OBJECT (label), "cursor_position");
+          g_object_notify (G_OBJECT (label), "selection_bound");
+          label->select_info->selection_anchor += new_text_length;
+        }
+
+      if (label->select_info->selection_end > *index)
+        {
+          label->select_info->selection_end += new_text_length;
+          g_object_notify (G_OBJECT (label), "selection_bound");
+        }
+    }
+
+  *index += new_text_length;
+
+  _gtk_label_clear_layout (GTK_LABEL (label));  
+  gtk_widget_queue_resize (GTK_WIDGET (label));
+
+  g_object_thaw_notify (G_OBJECT (label));
+}
+
+gboolean
+_gtk_label_delete_text (GtkLabel *label,
+                        int start_pos,
+                        int end_pos)
+{
+  int anchor, end;
+  GtkLabelPrivate *priv = GTK_LABEL_GET_PRIVATE (label);
+  gboolean retval = FALSE;
+
+  if (start_pos < 0)
+    start_pos = 0;
+  if (end_pos < 0 || end_pos > priv->n_bytes)
+    end_pos = priv->n_bytes;
+
+  if (start_pos < end_pos)
+    {
+      g_memmove (label->text + start_pos, label->text + end_pos, priv->n_bytes + 1 - end_pos);
+      priv->n_bytes -= (end_pos - start_pos);
+
+      anchor = label->select_info->selection_anchor;
+      if (anchor > start_pos)
+	anchor -= MIN (anchor, end_pos) - start_pos;
+
+      end = label->select_info->selection_end;
+      if (end > start_pos)
+	end -= MIN (end, end_pos) - start_pos;
+
+      /* We might have changed the selection */
+      _gtk_label_select_region_index (GTK_LABEL (label), anchor, end);
+
+      _gtk_label_clear_layout (GTK_LABEL (label));
+      gtk_widget_queue_resize (GTK_WIDGET (label));
+
+      g_object_notify (G_OBJECT (label), "label");
+      retval = TRUE;
+    }
+
+  return retval;
 }
 
+void
+_gtk_label_set_cursor_visible (GtkLabel *label, gboolean visible)
+{
+  GtkLabelPrivate *priv;
+
+  g_assert (GTK_IS_LABEL (label));
+  priv = GTK_LABEL_GET_PRIVATE (label);
+
+  priv->cursor_visible = visible;
+}
+
+gboolean
+_gtk_label_get_cursor_visible (GtkLabel *label)
+{
+  GtkLabelPrivate *priv;
+
+  g_assert (GTK_IS_LABEL (label));
+  priv = GTK_LABEL_GET_PRIVATE (label);
+
+  return priv->cursor_visible;
+}
+
+
 #define __GTK_LABEL_C__
 #include "gtkaliasdef.c"
Index: gtk/gtkeditablelabel.c
===================================================================
--- gtk/gtkeditablelabel.c	(revision 0)
+++ gtk/gtkeditablelabel.c	(revision 0)
@@ -0,0 +1,1103 @@
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 2002 Alexander Larsson <alexl@redhat.com>
+ * Copyright (C) 2008 Cosimo Cecchi <cosimoc@gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "config.h"
+#include "gtkclipboard.h"
+#include "gtkeditable.h"
+#include "gtkeditablelabel.h"
+#include "gtkimcontext.h"
+#include "gtkimmulticontext.h"
+#include "gtklabel.h"
+#include "gtklabelprivate.h"
+#include "gtkmarshalers.h"
+#include "gtkmenu.h"
+#include "gtkmenuitem.h"
+
+#include "gdk/gdkkeysyms.h"
+
+#include <string.h>
+
+#define GTK_EDITABLE_LABEL_GET_PRIVATE(obj) \
+(G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_EDITABLE_LABEL, GtkEditableLabelPrivate))
+
+struct _GtkEditableLabelPrivate
+{
+  gboolean need_im_reset;
+  GtkIMContext *im_context;
+  guint overwrite_mode : 1;
+  guint blink_timeout;
+  int preedit_length; /* length of preedit string, in bytes */
+  int preedit_cursor; /* offset of cursor within preedit string, in chars */
+};
+
+enum {
+  DELETE_FROM_CURSOR,
+  CUT_CLIPBOARD,
+  PASTE_CLIPBOARD,
+  TOGGLE_OVERWRITE,
+  LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+static void gtk_editable_label_editable_init (GtkEditableClass *iface);
+static void gtk_editable_label_check_cursor_blink (GtkEditableLabel *label);
+
+G_DEFINE_TYPE_EXTENDED (GtkEditableLabel, gtk_editable_label,
+                        GTK_TYPE_LABEL, 0, G_IMPLEMENT_INTERFACE (GTK_TYPE_EDITABLE,
+                                                                  gtk_editable_label_editable_init));
+
+static void
+gtk_editable_label_reset_im_context (GtkEditableLabel  *label)
+{
+  if (label->priv->need_im_reset)
+    {
+      label->priv->need_im_reset = FALSE;
+      gtk_im_context_reset (label->priv->im_context);
+    }
+}
+
+/* We display the cursor when
+ *
+ *  - the selection is empty, AND
+ *  - the widget has focus
+ */
+
+#define CURSOR_ON_MULTIPLIER 0.66
+#define CURSOR_OFF_MULTIPLIER 0.34
+#define CURSOR_PEND_MULTIPLIER 1.0
+
+static gboolean
+cursor_blinks (GtkEditableLabel *label)
+{
+  GtkSettings *settings = gtk_widget_get_settings (GTK_WIDGET (label));
+  gboolean blink;
+
+  if (GTK_WIDGET_HAS_FOCUS (label) && GTK_LABEL (label)->select_info)
+    {
+      g_object_get (settings, "gtk-cursor-blink", &blink, NULL);
+      return blink;
+    }
+  else
+    return FALSE;
+}
+
+static gint
+get_cursor_time (GtkEditableLabel *label)
+{
+  GtkSettings *settings = gtk_widget_get_settings (GTK_WIDGET (label));
+  gint time;
+
+  g_object_get (settings, "gtk-cursor-blink-time", &time, NULL);
+
+  return time;
+}
+
+static void
+show_cursor (GtkEditableLabel *label)
+{
+  if (!_gtk_label_get_cursor_visible (GTK_LABEL (label)))
+    {
+      _gtk_label_set_cursor_visible (GTK_LABEL (label), TRUE);
+
+      if (GTK_WIDGET_HAS_FOCUS (label) && GTK_LABEL (label)->select_info)
+	gtk_widget_queue_draw (GTK_WIDGET (label));
+    }
+}
+
+static void
+hide_cursor (GtkEditableLabel *label)
+{
+  if (_gtk_label_get_cursor_visible (GTK_LABEL (label)))
+    {
+      _gtk_label_set_cursor_visible (GTK_LABEL (label), FALSE);
+
+      if (GTK_WIDGET_HAS_FOCUS (label) && GTK_LABEL (label)->select_info)
+	gtk_widget_queue_draw (GTK_WIDGET (label));
+    }
+}
+
+/*
+ * Blink!
+ */
+static gint
+blink_cb (gpointer data)
+{
+  GtkEditableLabel *label;
+  GtkEditableLabelPrivate *priv;
+
+  label = GTK_EDITABLE_LABEL (data);
+  priv = label->priv;
+
+  if (!GTK_WIDGET_HAS_FOCUS (label))
+    {
+      g_warning ("GtkEditableLabel - did not receive focus-out-event. If you\n"
+		 "connect a handler to this signal, it must return\n"
+		 "FALSE so the entry gets the event as well");
+
+      gtk_editable_label_check_cursor_blink (label);
+
+      return FALSE;
+    }
+
+  g_assert (GTK_LABEL (label)->select_info);
+
+  if (_gtk_label_get_cursor_visible (GTK_LABEL (label)))
+    {
+      hide_cursor (label);
+      priv->blink_timeout = gdk_threads_add_timeout (get_cursor_time (label) * CURSOR_OFF_MULTIPLIER,
+                                                     blink_cb, label);
+    }
+  else
+    {
+      show_cursor (label);
+      priv->blink_timeout = gdk_threads_add_timeout (get_cursor_time (label) * CURSOR_ON_MULTIPLIER,
+                                                     blink_cb, label);
+    }
+
+  /* Remove ourselves */
+  return FALSE;
+}
+
+
+static void
+gtk_editable_label_pend_cursor_blink (GtkEditableLabel *label)
+{
+  GtkEditableLabelPrivate *priv = label->priv;
+
+  if (cursor_blinks (label))
+    {
+      if (priv->blink_timeout != 0)
+	g_source_remove (priv->blink_timeout);
+      
+      priv->blink_timeout = gdk_threads_add_timeout (get_cursor_time (label) * CURSOR_PEND_MULTIPLIER,
+                                                     blink_cb, label);
+      show_cursor (label);
+    }
+}
+
+static void
+gtk_editable_label_check_cursor_blink (GtkEditableLabel *label)
+{
+  GtkEditableLabelPrivate *priv = label->priv;
+
+  if (cursor_blinks (label))
+    {
+      if (!priv->blink_timeout)
+	{
+       	  show_cursor (label);
+	  priv->blink_timeout = gdk_threads_add_timeout (get_cursor_time (label) * CURSOR_ON_MULTIPLIER,
+						         blink_cb, label);
+	}
+    }
+  else
+    {
+      if (priv->blink_timeout)  
+	{ 
+	  g_source_remove (priv->blink_timeout);
+	  priv->blink_timeout = 0;
+	}
+
+      _gtk_label_set_cursor_visible (GTK_LABEL (label), TRUE);
+    }
+}
+
+static void
+gtk_editable_label_recompute (GtkEditableLabel *label)
+{
+  _gtk_label_clear_layout (GTK_LABEL (label));
+  gtk_editable_label_check_cursor_blink (label);
+}
+
+static void
+gtk_editable_label_cut_clipboard (GtkEditableLabel *edit_label)
+{
+  GtkLabel *label = GTK_LABEL (edit_label);
+
+  if (label->text)
+    {
+      gint start, end;
+      gint len;
+
+      start = MIN (label->select_info->selection_anchor,
+                   label->select_info->selection_end);
+      end = MAX (label->select_info->selection_anchor,
+                 label->select_info->selection_end);
+
+      len = strlen (label->text);
+
+      if (end > len)
+        end = len;
+
+      if (start > len)
+        start = len;
+
+      if (start != end)
+	{
+	  gtk_clipboard_set_text (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
+				  label->text + start, end - start);
+          start = g_utf8_pointer_to_offset (label->text, label->text + start);
+          end = g_utf8_pointer_to_offset (label->text, label->text + end);
+	  gtk_editable_delete_text (GTK_EDITABLE (edit_label), start, end);
+	}
+    }
+}
+
+static void
+paste_received (GtkClipboard *clipboard,
+		const gchar  *text,
+		gpointer      data)
+{
+  GtkLabel *label = GTK_LABEL (data);
+  GtkEditable *editable = GTK_EDITABLE (label);
+  gint tmp_pos;
+
+  if (text)
+    {
+      if (label->select_info->selection_end != label->select_info->selection_anchor)
+	gtk_editable_delete_selection (editable);
+
+      tmp_pos = g_utf8_pointer_to_offset (label->text,
+                                      label->text + label->select_info->selection_anchor);
+      gtk_editable_insert_text (editable, text, strlen (text), &tmp_pos);
+      tmp_pos = g_utf8_offset_to_pointer (label->text, tmp_pos) - label->text;
+      _gtk_label_select_region_index (label, tmp_pos, tmp_pos);
+    }
+
+  g_object_unref (label);
+}
+
+static void
+gtk_editable_label_paste (GtkEditableLabel *label,
+                          GdkAtom   selection)
+{
+  g_object_ref (label);
+  gtk_clipboard_request_text (gtk_widget_get_clipboard (GTK_WIDGET (label), selection),
+                              paste_received, label);
+}
+
+static void
+gtk_editable_label_paste_clipboard (GtkEditableLabel *label)
+{
+  gtk_editable_label_paste (label, GDK_NONE);
+}
+
+static void
+gtk_editable_label_toggle_overwrite (GtkEditableLabel *label)
+{
+  label->priv->overwrite_mode = !label->priv->overwrite_mode;
+  gtk_widget_queue_draw (GTK_WIDGET (label));
+}
+
+static gint
+gtk_editable_label_key_press (GtkWidget   *widget,
+                              GdkEventKey *event)
+{
+  GtkEditableLabel *label = GTK_EDITABLE_LABEL (widget);
+
+  gtk_editable_label_pend_cursor_blink (label);
+
+  if (gtk_im_context_filter_keypress (label->priv->im_context, event))
+    {
+      /*TODO gtk_editable_label_obscure_mouse_cursor (label);*/
+      label->priv->need_im_reset = TRUE;
+      return TRUE;
+    }
+
+  if (GTK_WIDGET_CLASS (gtk_editable_label_parent_class)->key_press_event (widget, event))
+    /* Activate key bindings
+     */
+    return TRUE;
+
+  return FALSE;
+}
+
+static gint
+gtk_editable_label_key_release (GtkWidget   *widget,
+				GdkEventKey *event)
+{
+  GtkEditableLabel *label = GTK_EDITABLE_LABEL (widget);
+
+  if (gtk_im_context_filter_keypress (label->priv->im_context, event))
+    {
+      label->priv->need_im_reset = TRUE;
+      return TRUE;
+    }
+
+  return GTK_WIDGET_CLASS (gtk_editable_label_parent_class)->key_release_event (widget, event);
+}
+
+static void
+gtk_editable_label_keymap_direction_changed (GdkKeymap *keymap,
+					     GtkEditableLabel  *label)
+{
+  gtk_widget_queue_draw (GTK_WIDGET (label));
+}
+
+static gint
+gtk_editable_label_focus_in (GtkWidget     *widget,
+			     GdkEventFocus *event)
+{
+  GtkEditableLabel *label = GTK_EDITABLE_LABEL (widget);
+
+  gtk_widget_queue_draw (widget);
+
+  label->priv->need_im_reset = TRUE;
+  gtk_im_context_focus_in (label->priv->im_context);
+
+  g_signal_connect (gdk_keymap_get_default (),
+		    "direction_changed",
+		    G_CALLBACK (gtk_editable_label_keymap_direction_changed), label);
+
+  gtk_editable_label_check_cursor_blink (label);
+
+  return FALSE;
+}
+
+static gint
+gtk_editable_label_focus_out (GtkWidget     *widget,
+			      GdkEventFocus *event)
+{
+  GtkEditableLabel *label = GTK_EDITABLE_LABEL (widget);
+
+  gtk_widget_queue_draw (widget);
+
+  label->priv->need_im_reset = TRUE;
+  gtk_im_context_focus_out (label->priv->im_context);
+
+  gtk_editable_label_check_cursor_blink (label);
+
+  g_signal_handlers_disconnect_by_func (gdk_keymap_get_default (),
+                                        (gpointer) gtk_editable_label_keymap_direction_changed,
+                                        label);
+
+  return FALSE;
+}
+
+static gboolean
+gtk_editable_label_focus (GtkWidget         *widget,
+			  GtkDirectionType   direction)
+{
+  /* We never want to be in the tab chain */
+  return FALSE;
+}
+
+static gint
+gtk_editable_label_move_forward_word (GtkEditableLabel *edit_label,
+				      gint      start)
+{
+  GtkLabel *label = GTK_LABEL (edit_label);
+  gint new_pos = g_utf8_pointer_to_offset (label->text,
+					   label->text + start);
+  gint length;
+
+  length = g_utf8_strlen (label->text, -1);
+  if (new_pos < length)
+    {
+      PangoLayout *layout;
+      PangoLogAttr *log_attrs;
+      gint n_attrs;
+
+      layout = gtk_label_get_layout (label);
+      pango_layout_get_log_attrs (layout, &log_attrs, &n_attrs);
+
+      /* Find the next word end */
+      new_pos++;
+      while (new_pos < n_attrs && !log_attrs[new_pos].is_word_end)
+	new_pos++;
+
+      g_free (log_attrs);
+    }
+
+  return g_utf8_offset_to_pointer (label->text, new_pos) - label->text;
+}
+
+
+static gint
+gtk_editable_label_move_backward_word (GtkEditableLabel *edit_label,
+				       gint      start)
+{
+  GtkLabel *label = GTK_LABEL (edit_label);
+  gint new_pos = g_utf8_pointer_to_offset (label->text,
+					   label->text + start);
+  
+  if (new_pos > 0)
+    {
+      PangoLayout *layout;
+      PangoLogAttr *log_attrs;
+      gint n_attrs;
+
+      /* this also does ensure_layout */
+      layout = gtk_label_get_layout (label);
+      pango_layout_get_log_attrs (layout, &log_attrs, &n_attrs);
+      
+      new_pos -= 1;
+
+      /* Find the previous word beginning */
+      while (new_pos > 0 && !log_attrs[new_pos].is_word_start)
+	new_pos--;
+
+      g_free (log_attrs);
+    }
+
+  return g_utf8_offset_to_pointer (label->text, new_pos) - label->text;
+}
+
+static gint
+gtk_editable_label_move_logically (GtkEditableLabel *edit_label,
+				   gint      start,
+				   gint      count)
+{ 
+  GtkLabel *label = GTK_LABEL (edit_label);
+  gint offset = g_utf8_pointer_to_offset (label->text, label->text + start);
+
+  if (label->text)
+    {
+      PangoLayout *layout;      
+      PangoLogAttr *log_attrs;
+      gint n_attrs;
+      gint length;
+
+      /* this also does ensure_layout */
+      layout = gtk_label_get_layout (label);
+      length = g_utf8_strlen (label->text, -1);
+      pango_layout_get_log_attrs (layout, &log_attrs, &n_attrs);
+
+      while (count > 0 && offset < length)
+	{
+	  do
+	    offset++;
+	  while (offset < length && !log_attrs[offset].is_cursor_position);
+	  
+	  count--;
+	}
+      while (count < 0 && offset > 0)
+	{
+	  do
+	    offset--;
+	  while (offset > 0 && !log_attrs[offset].is_cursor_position);
+	  
+	  count++;
+	}
+      
+      g_free (log_attrs);
+    }
+
+  return g_utf8_offset_to_pointer (label->text, offset) - label->text;
+}
+
+static void
+gtk_editable_label_delete_from_cursor (GtkEditableLabel *label,
+				       GtkDeleteType     type,
+				       gint              count)
+{
+  GtkEditable *editable = GTK_EDITABLE (label);
+  GtkLabel *glabel = GTK_LABEL (label);
+  gint start_pos, end_pos;
+
+  start_pos = end_pos = glabel->select_info->selection_anchor;
+
+  gtk_editable_label_reset_im_context (label);
+
+  if (glabel->select_info->selection_anchor != glabel->select_info->selection_end)
+    {
+      gtk_editable_delete_selection (editable);
+      return;
+    }
+
+  switch (type)
+    {
+    case GTK_DELETE_CHARS:
+      end_pos = gtk_editable_label_move_logically (label, start_pos, count);
+      start_pos = g_utf8_pointer_to_offset (glabel->text, glabel->text + start_pos);
+      end_pos = g_utf8_pointer_to_offset (glabel->text, glabel->text + end_pos);
+      gtk_editable_delete_text (GTK_EDITABLE (label), MIN (start_pos, end_pos), MAX (start_pos, end_pos));
+      break;
+    case GTK_DELETE_WORDS:
+      if (count < 0)
+	{
+	  /* Move to end of current word, or if not on a word, end of previous word */
+	  end_pos = gtk_editable_label_move_backward_word (label, end_pos);
+	  end_pos = gtk_editable_label_move_forward_word (label, end_pos);
+	}
+      else if (count > 0)
+	{
+	  /* Move to beginning of current word, or if not on a word, begining of next word */
+	  start_pos = gtk_editable_label_move_forward_word (label, start_pos);
+	  start_pos = gtk_editable_label_move_backward_word (label, start_pos);
+	}
+
+      /* Fall through */
+    case GTK_DELETE_WORD_ENDS:
+      while (count < 0)
+	{
+	  start_pos = gtk_editable_label_move_backward_word (label, start_pos);
+	  count++;
+	}
+      while (count > 0)
+	{
+	  end_pos = gtk_editable_label_move_forward_word (label, end_pos);
+	  count--;
+	}
+      start_pos = g_utf8_pointer_to_offset (glabel->text, glabel->text + start_pos);
+      end_pos = g_utf8_pointer_to_offset (glabel->text, glabel->text + end_pos);
+
+      gtk_editable_delete_text (GTK_EDITABLE (label), start_pos, end_pos);
+      break;
+    case GTK_DELETE_DISPLAY_LINE_ENDS:
+    case GTK_DELETE_PARAGRAPH_ENDS:
+      end_pos = g_utf8_pointer_to_offset (glabel->text, glabel->text +
+                                          glabel->select_info->selection_anchor);
+      if (count < 0)
+	gtk_editable_delete_text (GTK_EDITABLE (label), 0, end_pos);
+      else
+	gtk_editable_delete_text (GTK_EDITABLE (label), end_pos, -1);
+      break;
+    case GTK_DELETE_DISPLAY_LINES:
+    case GTK_DELETE_PARAGRAPHS:
+      gtk_editable_delete_text (GTK_EDITABLE (label), 0, -1);
+      break;
+    case GTK_DELETE_WHITESPACE:
+      /* TODO gtk_editable_label_delete_whitespace (label); */
+      break;
+    }
+  
+  gtk_editable_label_pend_cursor_blink (label);
+}
+
+/* Used for im_commit_cb and inserting Unicode chars */
+static void
+gtk_editable_label_enter_text (GtkEditableLabel *edit_label,
+			       const gchar    *str)
+{
+  GtkEditable *editable = GTK_EDITABLE (edit_label);
+  GtkLabel *label = GTK_LABEL (edit_label);
+  gint tmp_pos;
+  gboolean old_need_im_reset;
+
+  /* Never reset the im while commiting, as that resets possible im state */
+  old_need_im_reset = edit_label->priv->need_im_reset;
+  edit_label->priv->need_im_reset = FALSE;
+
+  if (label->select_info->selection_end != label->select_info->selection_anchor)
+    gtk_editable_delete_selection (editable);
+  else
+    {
+      if (edit_label->priv->overwrite_mode)
+        gtk_editable_label_delete_from_cursor (edit_label, GTK_DELETE_CHARS, 1);
+    }
+
+  tmp_pos = g_utf8_pointer_to_offset (label->text,
+                                      label->text + label->select_info->selection_anchor);
+  gtk_editable_insert_text (editable, str, strlen (str), &tmp_pos);
+  tmp_pos = g_utf8_offset_to_pointer (label->text, tmp_pos) - label->text;
+  _gtk_label_select_region_index (label, tmp_pos, tmp_pos);
+
+  edit_label->priv->need_im_reset = old_need_im_reset;
+}
+
+/* IM Context Callbacks
+ */
+
+static void
+gtk_editable_label_commit_cb (GtkIMContext *context,
+                              const gchar  *str,
+                              GtkEditableLabel  *label)
+{
+  gtk_editable_label_enter_text (label, str);
+}
+
+static void 
+gtk_editable_label_preedit_changed_cb (GtkIMContext *context,
+				       GtkEditableLabel  *label)
+{
+  gchar *preedit_string;
+  gint cursor_pos;
+
+  gtk_im_context_get_preedit_string (label->priv->im_context,
+				     &preedit_string, NULL,
+				     &cursor_pos);
+  label->priv->preedit_length = strlen (preedit_string);
+  cursor_pos = CLAMP (cursor_pos, 0, g_utf8_strlen (preedit_string, -1));
+  label->priv->preedit_cursor = cursor_pos;
+  g_free (preedit_string);
+
+  gtk_editable_label_recompute (label);
+  gtk_widget_queue_resize (GTK_WIDGET (label));
+}
+
+static gboolean
+gtk_editable_label_retrieve_surrounding_cb (GtkIMContext *context,
+					    GtkEditableLabel  *edit_label)
+{
+  GtkLabel *label = GTK_LABEL (edit_label);
+
+  gtk_im_context_set_surrounding (context,
+				  label->text,
+				  strlen (label->text) + 1,
+				  label->select_info->selection_end);
+
+  return TRUE;
+}
+
+static gboolean
+gtk_editable_label_delete_surrounding_cb (GtkIMContext *context,
+					  gint          offset,
+					  gint          n_chars,
+					  GtkEditableLabel  *edit_label)
+{
+  GtkLabel *label = GTK_LABEL (edit_label);
+  gint current_pos;
+
+  current_pos = g_utf8_pointer_to_offset (label->text, label->text + label->select_info->selection_anchor);
+  gtk_editable_delete_text (GTK_EDITABLE (edit_label),
+			    current_pos + offset, 
+			    current_pos + offset + n_chars);
+
+  return TRUE;
+}
+
+static void
+gtk_editable_label_delete_cb (GtkMenuItem *item,
+                              GtkLabel *label)
+{
+  GtkEditable *editable = GTK_EDITABLE (label);
+  gint start, end;
+
+  if (gtk_editable_get_selection_bounds (editable, &start, &end))
+	gtk_editable_delete_text (editable, start, end);
+}
+
+static void
+gtk_editable_label_populate_popup (GtkLabel *label,
+                                   GtkMenu *menu)
+{
+  GtkLabelSelectionInfo *sel_info = label->select_info;
+  gboolean have_selection;
+
+  have_selection = sel_info->selection_anchor != sel_info->selection_end;
+  gtk_widget_set_sensitive (GTK_WIDGET (sel_info->cut_item), have_selection);
+
+  gtk_widget_set_sensitive (GTK_WIDGET (sel_info->delete_item), have_selection);
+  g_signal_connect (sel_info->delete_item, "activate",
+                    G_CALLBACK (gtk_editable_label_delete_cb), label);
+  gtk_widget_set_sensitive (GTK_WIDGET (sel_info->paste_item), sel_info->clipboard_has_text);
+}
+
+/* Editable Implementations */
+
+static void
+editable_insert_text_emit  (GtkEditable *editable,
+                            const gchar *new_text,
+                            gint         new_text_length,
+                            gint        *position)
+{
+  gchar buf[64];
+  gchar *text;
+  int text_length;
+  GtkLabel *label = GTK_LABEL (editable);
+
+  text_length = g_utf8_strlen (label->text, -1);
+
+  if (*position < 0 || *position > text_length)
+    *position = text_length;
+
+  g_object_ref (editable);
+
+  if (new_text_length <= 63)
+    text = buf;
+  else
+    text = g_new (gchar, new_text_length + 1);
+
+  text[new_text_length] = '\0';
+  strncpy (text, new_text, new_text_length);
+
+  g_signal_emit_by_name (editable, "insert_text", text, new_text_length, position);
+
+  if (new_text_length > 63)
+    g_free (text);
+
+  g_object_unref (editable);
+}
+
+static void
+editable_delete_text_emit (GtkEditable *editable,
+                           gint         start_pos,
+                           gint         end_pos)
+{
+  int text_length;
+  GtkLabel *label = GTK_LABEL (editable);
+
+  text_length = g_utf8_strlen (label->text, -1);
+
+  if (end_pos < 0 || end_pos > text_length)
+    end_pos = text_length;
+  if (start_pos < 0)
+    start_pos = 0;
+  if (start_pos > end_pos)
+    start_pos = end_pos;
+
+  g_object_ref (editable);
+
+  g_signal_emit_by_name (editable, "delete_text", start_pos, end_pos);
+
+  g_object_unref (editable);
+}
+
+static void
+editable_insert_text (GtkEditable *editable,
+                      const gchar *new_text,
+                      gint         new_text_length,
+                      gint        *position)
+{
+  gint index;
+  GtkLabel *label = GTK_LABEL (editable);
+
+  if (new_text_length < 0)
+    new_text_length = strlen (new_text);
+
+  index = g_utf8_offset_to_pointer (label->text, *position) - label->text;
+
+  _gtk_label_insert_text (label,
+                          new_text,
+                          new_text_length,
+                          &index);
+
+  g_signal_emit_by_name (editable, "changed");
+
+  *position = g_utf8_pointer_to_offset (label->text, label->text + index);
+}
+
+static void
+editable_delete_text (GtkEditable *editable,
+                      gint         start_pos,
+                      gint         end_pos)
+{
+  int text_length;
+  gint start_index, end_index;
+  GtkLabel *label = GTK_LABEL (editable);
+
+  text_length = g_utf8_strlen (label->text, -1);
+
+  if (end_pos < 0 || end_pos > text_length)
+    end_pos = text_length;
+  if (start_pos < 0)
+    start_pos = 0;
+  if (start_pos > end_pos)
+    start_pos = end_pos;
+
+  start_index = g_utf8_offset_to_pointer (label->text, start_pos) - label->text;
+  end_index = g_utf8_offset_to_pointer (label->text, end_pos) - label->text;
+
+  if (_gtk_label_delete_text (label, start_index, end_index))
+    g_signal_emit_by_name (editable, "changed");
+}
+
+static gchar *    
+editable_get_chars (GtkEditable   *editable,
+                    gint           start_pos,
+                    gint           end_pos)
+{
+  GtkLabel *label = GTK_LABEL (editable);
+  int text_length;
+  gint start_index, end_index;
+
+  text_length = g_utf8_strlen (label->text, -1);
+
+  if (end_pos < 0 || end_pos > text_length)
+    end_pos = text_length;
+  if (start_pos < 0)
+    start_pos = 0;
+  if (start_pos > end_pos)
+    start_pos = end_pos;
+
+  start_index = g_utf8_offset_to_pointer (label->text, start_pos) - label->text;
+  end_index = g_utf8_offset_to_pointer (label->text, end_pos) - label->text;
+
+  return g_strndup (label->text + start_index, end_index - start_index);
+}
+
+static void
+editable_set_selection_bounds (GtkEditable *editable,
+                               gint         start,
+                               gint         end)
+{
+  GtkLabel *label = GTK_LABEL (editable);
+  int text_length;
+  gint start_index, end_index;
+
+  text_length = g_utf8_strlen (label->text, -1);
+
+  if (end < 0 || end > text_length)
+    end = text_length;
+  if (start < 0)
+    start = text_length;
+  if (start > text_length)
+    start = text_length;
+
+  gtk_editable_label_reset_im_context (GTK_EDITABLE_LABEL (label));
+
+  start_index = g_utf8_offset_to_pointer (label->text, start) - label->text;
+  end_index = g_utf8_offset_to_pointer (label->text, end) - label->text;
+
+  _gtk_label_select_region_index (label, start_index, end_index);
+}
+
+static gboolean
+editable_get_selection_bounds (GtkEditable *editable,
+			       gint        *start,
+			       gint        *end)
+{
+  GtkLabel *label = GTK_LABEL (editable);
+
+  *start = g_utf8_pointer_to_offset (label->text, label->text + label->select_info->selection_anchor);
+  *end = g_utf8_pointer_to_offset (label->text, label->text + label->select_info->selection_end);
+
+  return (label->select_info->selection_anchor != label->select_info->selection_end);
+}
+
+static void
+editable_real_set_position (GtkEditable *editable,
+			    gint         position)
+{
+  GtkLabel *label = GTK_LABEL (editable);
+  int text_length;
+  int index;
+
+  text_length = g_utf8_strlen (label->text, -1);
+
+  if (position < 0 || position > text_length)
+    position = text_length;
+
+  index = g_utf8_offset_to_pointer (label->text, position) - label->text;
+
+  if (index != label->select_info->selection_anchor ||
+      index != label->select_info->selection_end)
+    {
+      _gtk_label_select_region_index (label, index, index);
+    }
+}
+
+static gint
+editable_get_position (GtkEditable *editable)
+{
+  GtkLabel *label = GTK_LABEL (editable);
+
+  return g_utf8_pointer_to_offset (label->text, label->text + label->select_info->selection_anchor);
+}
+
+static void
+gtk_editable_label_finalize (GObject *object)
+{
+  GtkEditableLabelPrivate *priv = GTK_EDITABLE_LABEL (object)->priv;
+
+  if (priv->im_context)
+    {
+      g_object_unref (priv->im_context);
+      priv->im_context = NULL;
+    }
+  if (priv->blink_timeout)
+    {
+      g_source_remove (priv->blink_timeout);
+      priv->blink_timeout = 0;
+    }
+
+  G_OBJECT_CLASS (gtk_editable_label_parent_class)->finalize (object);
+}
+
+static void
+gtk_editable_label_class_init (GtkEditableLabelClass *klass)
+{
+  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+  GtkObjectClass *object_class = GTK_OBJECT_CLASS (klass);
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  GtkLabelClass *label_class = GTK_LABEL_CLASS (klass);
+  GtkBindingSet *binding_set;
+  
+  widget_class->key_press_event = gtk_editable_label_key_press;
+  widget_class->key_release_event = gtk_editable_label_key_release;
+  widget_class->focus = gtk_editable_label_focus;
+  widget_class->focus_in_event = gtk_editable_label_focus_in;
+  widget_class->focus_out_event = gtk_editable_label_focus_out;
+
+  label_class->populate_popup = gtk_editable_label_populate_popup;
+
+  gobject_class->finalize = gtk_editable_label_finalize;
+
+  klass->delete_from_cursor = gtk_editable_label_delete_from_cursor;
+  klass->cut_clipboard = gtk_editable_label_cut_clipboard;
+  klass->paste_clipboard = gtk_editable_label_paste_clipboard;
+  klass->toggle_overwrite = gtk_editable_label_toggle_overwrite;
+
+  signals[DELETE_FROM_CURSOR] = 
+    g_signal_new ("delete_from_cursor",
+		  G_TYPE_FROM_CLASS (object_class),
+		  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+		  G_STRUCT_OFFSET (GtkEditableLabelClass, delete_from_cursor),
+		  NULL, NULL, 
+		  _gtk_marshal_VOID__ENUM_INT,
+		  G_TYPE_NONE, 2, GTK_TYPE_DELETE_TYPE, G_TYPE_INT);
+  
+  signals[CUT_CLIPBOARD] =
+    g_signal_new ("cut_clipboard",
+		  G_TYPE_FROM_CLASS (object_class),
+		  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+		  G_STRUCT_OFFSET (GtkEditableLabelClass, cut_clipboard),
+		  NULL, NULL, 
+		  _gtk_marshal_VOID__VOID,
+		  G_TYPE_NONE, 0);
+
+  signals[PASTE_CLIPBOARD] =
+    g_signal_new ("paste_clipboard",
+		  G_TYPE_FROM_CLASS (object_class),
+		  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+		  G_STRUCT_OFFSET (GtkEditableLabelClass, paste_clipboard),
+		  NULL, NULL, 
+		  _gtk_marshal_VOID__VOID,
+		  G_TYPE_NONE, 0);
+
+  signals[TOGGLE_OVERWRITE] =
+    g_signal_new ("toggle_overwrite",
+		  G_TYPE_FROM_CLASS (object_class),
+		  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+		  G_STRUCT_OFFSET (GtkEditableLabelClass, toggle_overwrite),
+		  NULL, NULL, 
+		  _gtk_marshal_VOID__VOID,
+		  G_TYPE_NONE, 0);
+  /*
+   * Key bindings
+   */
+
+  binding_set = gtk_binding_set_by_class (klass);
+
+  _gtk_label_add_move_binding (binding_set, GDK_Up, 0,
+                               GTK_MOVEMENT_DISPLAY_LINES, -1);
+
+  _gtk_label_add_move_binding (binding_set, GDK_KP_Up, 0,
+                               GTK_MOVEMENT_DISPLAY_LINES, -1);
+  
+  _gtk_label_add_move_binding (binding_set, GDK_Down, 0,
+                               GTK_MOVEMENT_DISPLAY_LINES, 1);
+
+  _gtk_label_add_move_binding (binding_set, GDK_KP_Down, 0,
+                               GTK_MOVEMENT_DISPLAY_LINES, 1);
+  
+  /* Deleting text */
+  gtk_binding_entry_add_signal (binding_set, GDK_Delete, 0,
+				"delete_from_cursor", 2,
+				G_TYPE_ENUM, GTK_DELETE_CHARS,
+				G_TYPE_INT, 1);
+
+  gtk_binding_entry_add_signal (binding_set, GDK_KP_Delete, 0,
+				"delete_from_cursor", 2,
+				G_TYPE_ENUM, GTK_DELETE_CHARS,
+				G_TYPE_INT, 1);
+  
+  gtk_binding_entry_add_signal (binding_set, GDK_BackSpace, 0,
+				"delete_from_cursor", 2,
+				G_TYPE_ENUM, GTK_DELETE_CHARS,
+				G_TYPE_INT, -1);
+
+  /* Make this do the same as Backspace, to help with mis-typing */
+  gtk_binding_entry_add_signal (binding_set, GDK_BackSpace, GDK_SHIFT_MASK,
+                                "delete_from_cursor", 2,
+                                G_TYPE_ENUM, GTK_DELETE_CHARS,
+                                G_TYPE_INT, -1);
+
+  gtk_binding_entry_add_signal (binding_set, GDK_Delete, GDK_CONTROL_MASK,
+				"delete_from_cursor", 2,
+				G_TYPE_ENUM, GTK_DELETE_WORD_ENDS,
+				G_TYPE_INT, 1);
+
+  gtk_binding_entry_add_signal (binding_set, GDK_KP_Delete, GDK_CONTROL_MASK,
+				"delete_from_cursor", 2,
+				G_TYPE_ENUM, GTK_DELETE_WORD_ENDS,
+				G_TYPE_INT, 1);
+  
+  gtk_binding_entry_add_signal (binding_set, GDK_BackSpace, GDK_CONTROL_MASK,
+				"delete_from_cursor", 2,
+				G_TYPE_ENUM, GTK_DELETE_WORD_ENDS,
+				G_TYPE_INT, -1);
+  /* clipboard */
+  gtk_binding_entry_add_signal (binding_set, GDK_x, GDK_CONTROL_MASK,
+				"cut_clipboard", 0);
+  gtk_binding_entry_add_signal (binding_set, GDK_v, GDK_CONTROL_MASK,
+				"paste_clipboard", 0);
+ 
+  gtk_binding_entry_add_signal (binding_set, GDK_Delete, GDK_SHIFT_MASK,
+				"cut_clipboard", 0);
+  gtk_binding_entry_add_signal (binding_set, GDK_Insert, GDK_CONTROL_MASK,
+				"copy_clipboard", 0);
+  gtk_binding_entry_add_signal (binding_set, GDK_Insert, GDK_SHIFT_MASK,
+				"paste_clipboard", 0);
+  /* Overwrite */
+  gtk_binding_entry_add_signal (binding_set, GDK_Insert, 0,
+				"toggle_overwrite", 0);
+  gtk_binding_entry_add_signal (binding_set, GDK_KP_Insert, 0,
+				"toggle_overwrite", 0);
+
+  g_type_class_add_private (klass, sizeof (GtkEditableLabelPrivate));
+}
+
+static void
+gtk_editable_label_init (GtkEditableLabel *label)
+{
+  GtkEditableLabelPrivate *priv = label->priv =
+    GTK_EDITABLE_LABEL_GET_PRIVATE (label);
+
+  gtk_label_set_selectable (GTK_LABEL (label), TRUE);
+
+  /* This object is completely private. No external entity can gain a reference
+   * to it; so we create it here and destroy it in finalize().
+   */
+  priv->im_context = gtk_im_multicontext_new ();
+
+  g_signal_connect (G_OBJECT (priv->im_context), "commit",
+		    G_CALLBACK (gtk_editable_label_commit_cb), label);
+  g_signal_connect (G_OBJECT (priv->im_context), "preedit_changed",
+		    G_CALLBACK (gtk_editable_label_preedit_changed_cb), label);
+  g_signal_connect (G_OBJECT (priv->im_context), "retrieve_surrounding",
+		    G_CALLBACK (gtk_editable_label_retrieve_surrounding_cb), label);
+  g_signal_connect (G_OBJECT (priv->im_context), "delete_surrounding",
+		    G_CALLBACK (gtk_editable_label_delete_surrounding_cb), label);
+}
+
+static void
+gtk_editable_label_editable_init (GtkEditableClass *iface)
+{
+  iface->do_insert_text = editable_insert_text_emit;
+  iface->do_delete_text = editable_delete_text_emit;
+  iface->insert_text = editable_insert_text;
+  iface->delete_text = editable_delete_text;
+  iface->get_chars = editable_get_chars;
+  iface->set_selection_bounds = editable_set_selection_bounds;
+  iface->get_selection_bounds = editable_get_selection_bounds;
+  iface->set_position = editable_real_set_position;
+  iface->get_position = editable_get_position;
+}
+
+GtkWidget *
+gtk_editable_label_new (void)
+{
+  GtkWidget *label;
+
+  label = g_object_new (GTK_TYPE_EDITABLE_LABEL, NULL);
+
+  return label;
+}
Index: gtk/gtkeditablelabel.h
===================================================================
--- gtk/gtkeditablelabel.h	(revision 0)
+++ gtk/gtkeditablelabel.h	(revision 0)
@@ -0,0 +1,66 @@
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 2002 Alexander Larsson <alexl@redhat.com>
+ * Copyright (C) 2008 Cosimo Cecchi <cosimoc@gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+ 
+#if defined(GTK_DISABLE_SINGLE_INCLUDES) && !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
+#error "Only <gtk/gtk.h> can be included directly."
+#endif
+
+#ifndef __GTK_EDITABLE_LABEL_H__
+#define __GTK_EDITABLE_LABEL_H__
+
+#include <gtk/gtklabel.h>
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_EDITABLE_LABEL  (gtk_editable_label_get_type ())
+#define GTK_EDITABLE_LABEL(obj)		  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_EDITABLE_LABEL, GtkEditableLabel))
+#define GTK_EDITABLE_LABEL_CLASS(klass)	  (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_EDITABLE_LABEL, GtkEditableLabelClass))
+#define GTK_IS_EDITABLE_LABEL(obj)	  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_EDITABLE_LABEL))
+#define GTK_IS_EDITABLE_LABEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_EDITABLE_LABEL))
+#define GTK_EDITABLE_LABEL_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_EDITABLE_LABEL, GtkEditableLabelClass))
+
+typedef struct _GtkEditableLabel       GtkEditableLabel;
+typedef struct _GtkEditableLabelPrivate GtkEditableLabelPrivate;
+typedef struct _GtkEditableLabelClass  GtkEditableLabelClass;
+
+struct _GtkEditableLabel
+{
+  GtkLabel parent;
+  GtkEditableLabelPrivate *priv;
+};
+
+struct _GtkEditableLabelClass
+{
+  GtkLabelClass parent;
+  void (* insert_at_cursor)   (GtkEditableLabel      *label,
+			       const gchar   *str);
+  void (* delete_from_cursor) (GtkEditableLabel      *label,
+			       GtkDeleteType type,
+			       gint          count);
+  void (* cut_clipboard)      (GtkEditableLabel     *label);
+  void (* paste_clipboard)    (GtkEditableLabel     *label);
+  void (* toggle_overwrite)   (GtkEditableLabel     *label);
+};
+
+GType gtk_editable_label_get_type (void);
+GtkWidget * gtk_editable_label_new (void);
+
+G_END_DECLS
+
+#endif /* __GTK_EDITABLE_LABEL_H__ */
