File gtk-cvs.dif of Package gtk

diff -ruN gtk+-1.2.10/gdk/gdkevents.c gtk-n/gdk/gdkevents.c
--- gtk+-1.2.10/gdk/gdkevents.c	Sun Dec  3 17:02:49 2000
+++ gtk-n/gdk/gdkevents.c	Thu Jan 31 08:56:05 2002
@@ -383,6 +383,7 @@
 struct _GdkExposeInfo
 {
   Window window;
+  GdkWindowPrivate *toplevel_window;
   gboolean seen_nonmatching;
 };
 
@@ -400,10 +401,21 @@
    * we'll get a whole bunch of them interspersed with
    * expose events.
    */
-  if (xevent->xany.type != Expose && 
-      xevent->xany.type != GravityNotify)
+  switch (xevent->xany.type)
     {
+    case Expose:
+    case GravityNotify:
+      break;
+    case ConfigureNotify:
+      if (xevent->xconfigure.window != info->toplevel_window->xwindow)
+	break;
+      if (xevent->xconfigure.width == info->toplevel_window->width &&
+	  xevent->xconfigure.height == info->toplevel_window->height)
+	break;
+      /* Fall through */
+    default:
       info->seen_nonmatching = TRUE;
+      break;
     }
 
   if (info->seen_nonmatching ||
@@ -429,6 +441,7 @@
   GdkEvent event;
 
   info.window = xevent->xany.window;
+  info.toplevel_window = (GdkWindowPrivate *) gdk_window_get_toplevel (window);
   info.seen_nonmatching = FALSE;
   
   rect1.x = xevent->xexpose.x;
diff -ruN gtk+-1.2.10/gdk/gdkfont.c gtk-n/gdk/gdkfont.c
--- gtk+-1.2.10/gdk/gdkfont.c	Mon Apr  2 04:31:25 2001
+++ gtk-n/gdk/gdkfont.c	Thu Jan 31 08:56:23 2002
@@ -26,6 +26,7 @@
 
 #include <X11/Xlib.h>
 #include <X11/Xos.h>
+#include <langinfo.h>
 #include "gdk.h"
 #include "gdkprivate.h"
 
@@ -173,9 +174,24 @@
   if (missing_charset_count)
     {
       gint i;
-      g_warning ("Missing charsets in FontSet creation\n");
-      for (i=0;i<missing_charset_count;i++)
-	g_warning ("    %s\n", missing_charset_list[i]);
+      const char *codeset;
+
+      codeset = nl_langinfo (CODESET);
+
+      /* Hack - UTF-8 is likely to be rendered with a list of
+       * possible legacy fallback charsets, so a failure here
+       * shouldn't be warned about. But we don't want to suppress
+       * this warning in general, since for other character sets
+       * it gives a useful indication of what went wrong.
+       */
+      if (g_strcasecmp (codeset, "utf-8") != 0 &&
+	  g_strcasecmp (codeset, "utf8") != 0)
+	{
+	  g_warning ("Missing charsets in FontSet creation\n");
+	  for (i=0;i<missing_charset_count;i++)
+	    g_warning ("    %s\n", missing_charset_list[i]);
+	}
+      
       XFreeStringList (missing_charset_list);
     }
 
@@ -445,7 +461,6 @@
   GdkFontPrivate *private;
   XCharStruct *chars;
   gint width;
-  guint ch = character & 0xff;  /* get rid of sign-extension */
   XFontStruct *xfont;
   XFontSet fontset;
 
@@ -458,21 +473,7 @@
     case GDK_FONT_FONT:
       /* only 8 bits characters are considered here */
       xfont = (XFontStruct *) private->xfont;
-      if ((xfont->min_byte1 == 0) &&
-	  (xfont->max_byte1 == 0) &&
-	  (ch >= xfont->min_char_or_byte2) &&
-	  (ch <= xfont->max_char_or_byte2))
-	{
-	  chars = xfont->per_char;
-	  if (chars)
-	    width = chars[ch - xfont->min_char_or_byte2].width;
-	  else
-	    width = xfont->min_bounds.width;
-	}
-      else
-	{
-	  width = XTextWidth (xfont, &character, 1);
-	}
+      width = XTextWidth (xfont, &character, 1);
       break;
     case GDK_FONT_FONTSET:
       fontset = (XFontSet) private->xfont;
diff -ruN gtk+-1.2.10/gdk/gdkfont.c.orig gtk-n/gdk/gdkfont.c.orig
--- gtk+-1.2.10/gdk/gdkfont.c.orig	Thu Jan  1 01:00:00 1970
+++ gtk-n/gdk/gdkfont.c.orig	Mon Apr  2 04:31:25 2001
@@ -0,0 +1,897 @@
+/* GDK - The GIMP Drawing Kit
+ * 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 Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-1999.  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/. 
+ */
+
+#include <X11/Xlib.h>
+#include <X11/Xos.h>
+#include "gdk.h"
+#include "gdkprivate.h"
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#  if STDC_HEADERS
+#    include <string.h>
+#  endif
+#endif
+
+#ifdef USE_NATIVE_LOCALE
+#include <stdlib.h>
+#endif
+
+static GHashTable *font_name_hash = NULL;
+static GHashTable *fontset_name_hash = NULL;
+
+#define FONT_XFONT(private)  ((XFontStruct *)(private)->xfont)
+#define FONT_IS_8BIT(private) ((FONT_XFONT(private)->min_byte1 == 0) && \
+			       (FONT_XFONT(private)->max_byte1 == 0))
+
+static void
+gdk_font_hash_insert (GdkFontType type, GdkFont *font, const gchar *font_name)
+{
+  GdkFontPrivate *private = (GdkFontPrivate *)font;
+  GHashTable **hashp = (type == GDK_FONT_FONT) ?
+    &font_name_hash : &fontset_name_hash;
+
+  if (!*hashp)
+    *hashp = g_hash_table_new (g_str_hash, g_str_equal);
+
+  private->names = g_slist_prepend (private->names, g_strdup (font_name));
+  g_hash_table_insert (*hashp, private->names->data, font);
+}
+
+static void
+gdk_font_hash_remove (GdkFontType type, GdkFont *font)
+{
+  GdkFontPrivate *private = (GdkFontPrivate *)font;
+  GSList *tmp_list;
+  GHashTable *hash = (type == GDK_FONT_FONT) ?
+    font_name_hash : fontset_name_hash;
+
+  tmp_list = private->names;
+  while (tmp_list)
+    {
+      g_hash_table_remove (hash, tmp_list->data);
+      g_free (tmp_list->data);
+      
+      tmp_list = tmp_list->next;
+    }
+
+  g_slist_free (private->names);
+  private->names = NULL;
+}
+
+static GdkFont *
+gdk_font_hash_lookup (GdkFontType type, const gchar *font_name)
+{
+  GdkFont *result;
+  GHashTable *hash = (type == GDK_FONT_FONT) ?
+    font_name_hash : fontset_name_hash;
+
+  if (!hash)
+    return NULL;
+  else
+    {
+      result = g_hash_table_lookup (hash, font_name);
+      if (result)
+	gdk_font_ref (result);
+      
+      return result;
+    }
+}
+
+GdkFont*
+gdk_font_load (const gchar *font_name)
+{
+  GdkFont *font;
+  GdkFontPrivate *private;
+  XFontStruct *xfont;
+
+  g_return_val_if_fail (font_name != NULL, NULL);
+
+  font = gdk_font_hash_lookup (GDK_FONT_FONT, font_name);
+  if (font)
+    return font;
+
+  xfont = XLoadQueryFont (gdk_display, font_name);
+  if (xfont == NULL)
+    return NULL;
+
+  font = gdk_font_lookup (xfont->fid);
+  if (font != NULL)
+    {
+      private = (GdkFontPrivate *) font;
+      if (xfont != private->xfont)
+	XFreeFont (gdk_display, xfont);
+
+      gdk_font_ref (font);
+    }
+  else
+    {
+      private = g_new (GdkFontPrivate, 1);
+      private->xdisplay = gdk_display;
+      private->xfont = xfont;
+      private->ref_count = 1;
+      private->names = NULL;
+ 
+      font = (GdkFont*) private;
+      font->type = GDK_FONT_FONT;
+      font->ascent =  xfont->ascent;
+      font->descent = xfont->descent;
+
+      gdk_xid_table_insert (&xfont->fid, font);
+    }
+
+  gdk_font_hash_insert (GDK_FONT_FONT, font, font_name);
+
+  return font;
+}
+
+GdkFont*
+gdk_fontset_load (const gchar *fontset_name)
+{
+  GdkFont *font;
+  GdkFontPrivate *private;
+  XFontSet fontset;
+  gint  missing_charset_count;
+  gchar **missing_charset_list;
+  gchar *def_string;
+
+  font = gdk_font_hash_lookup (GDK_FONT_FONTSET, fontset_name);
+  if (font)
+    return font;
+
+  private = g_new (GdkFontPrivate, 1);
+  font = (GdkFont*) private;
+
+  private->xdisplay = gdk_display;
+  fontset = XCreateFontSet (gdk_display, fontset_name,
+			    &missing_charset_list, &missing_charset_count,
+			    &def_string);
+
+  if (missing_charset_count)
+    {
+      gint i;
+      g_warning ("Missing charsets in FontSet creation\n");
+      for (i=0;i<missing_charset_count;i++)
+	g_warning ("    %s\n", missing_charset_list[i]);
+      XFreeStringList (missing_charset_list);
+    }
+
+  private->ref_count = 1;
+
+  if (!fontset)
+    {
+      g_free (font);
+      return NULL;
+    }
+  else
+    {
+      gint num_fonts;
+      gint i;
+      XFontStruct **font_structs;
+      gchar **font_names;
+      
+      private->xfont = fontset;
+      font->type = GDK_FONT_FONTSET;
+      num_fonts = XFontsOfFontSet (fontset, &font_structs, &font_names);
+
+      font->ascent = font->descent = 0;
+      
+      for (i = 0; i < num_fonts; i++)
+	{
+	  font->ascent = MAX (font->ascent, font_structs[i]->ascent);
+	  font->descent = MAX (font->descent, font_structs[i]->descent);
+	}
+
+      private->names = NULL;
+      gdk_font_hash_insert (GDK_FONT_FONTSET, font, fontset_name);
+      
+      return font;
+    }
+}
+
+GdkFont*
+gdk_font_ref (GdkFont *font)
+{
+  GdkFontPrivate *private;
+
+  g_return_val_if_fail (font != NULL, NULL);
+
+  private = (GdkFontPrivate*) font;
+  private->ref_count += 1;
+  return font;
+}
+
+void
+gdk_font_unref (GdkFont *font)
+{
+  GdkFontPrivate *private;
+  private = (GdkFontPrivate*) font;
+
+  g_return_if_fail (font != NULL);
+  g_return_if_fail (private->ref_count > 0);
+
+  private->ref_count -= 1;
+  if (private->ref_count == 0)
+    {
+      gdk_font_hash_remove (font->type, font);
+      
+      switch (font->type)
+	{
+	case GDK_FONT_FONT:
+	  gdk_xid_table_remove (((XFontStruct *) private->xfont)->fid);
+	  XFreeFont (private->xdisplay, (XFontStruct *) private->xfont);
+	  break;
+	case GDK_FONT_FONTSET:
+	  XFreeFontSet (private->xdisplay, (XFontSet) private->xfont);
+	  break;
+	default:
+	  g_error ("unknown font type.");
+	  break;
+	}
+      g_free (font);
+    }
+}
+
+gint
+gdk_font_id (const GdkFont *font)
+{
+  const GdkFontPrivate *font_private;
+
+  g_return_val_if_fail (font != NULL, 0);
+
+  font_private = (const GdkFontPrivate*) font;
+
+  if (font->type == GDK_FONT_FONT)
+    {
+      return ((XFontStruct *) font_private->xfont)->fid;
+    }
+  else
+    {
+      return 0;
+    }
+}
+
+gboolean
+gdk_font_equal (const GdkFont *fonta,
+                const GdkFont *fontb)
+{
+  const GdkFontPrivate *privatea;
+  const GdkFontPrivate *privateb;
+
+  g_return_val_if_fail (fonta != NULL, FALSE);
+  g_return_val_if_fail (fontb != NULL, FALSE);
+
+  privatea = (const GdkFontPrivate*) fonta;
+  privateb = (const GdkFontPrivate*) fontb;
+
+  if (fonta->type == GDK_FONT_FONT && fontb->type == GDK_FONT_FONT)
+    {
+      return (((XFontStruct *) privatea->xfont)->fid ==
+	      ((XFontStruct *) privateb->xfont)->fid);
+    }
+  else if (fonta->type == GDK_FONT_FONTSET && fontb->type == GDK_FONT_FONTSET)
+    {
+      gchar *namea, *nameb;
+
+      namea = XBaseFontNameListOfFontSet((XFontSet) privatea->xfont);
+      nameb = XBaseFontNameListOfFontSet((XFontSet) privateb->xfont);
+      
+      return (strcmp(namea, nameb) == 0);
+    }
+  else
+    /* fontset != font */
+    return FALSE;
+}
+
+gint
+gdk_string_width (GdkFont     *font,
+		  const gchar *string)
+{
+  GdkFontPrivate *font_private;
+  gint width;
+  XFontStruct *xfont;
+  XFontSet fontset;
+
+  g_return_val_if_fail (font != NULL, -1);
+  g_return_val_if_fail (string != NULL, -1);
+
+  font_private = (GdkFontPrivate*) font;
+
+  switch (font->type)
+    {
+    case GDK_FONT_FONT:
+      xfont = (XFontStruct *) font_private->xfont;
+      if ((xfont->min_byte1 == 0) && (xfont->max_byte1 == 0))
+	{
+	  width = XTextWidth (xfont, string, strlen (string));
+	}
+      else
+	{
+	  width = XTextWidth16 (xfont, (XChar2b *) string, strlen (string) / 2);
+	}
+      break;
+    case GDK_FONT_FONTSET:
+      fontset = (XFontSet) font_private->xfont;
+      width = XmbTextEscapement (fontset, string, strlen(string));
+      break;
+    default:
+      width = 0;
+    }
+
+  return width;
+}
+
+gint
+gdk_text_width (GdkFont      *font,
+		const gchar  *text,
+		gint          text_length)
+{
+  GdkFontPrivate *private;
+  gint width;
+  XFontStruct *xfont;
+  XFontSet fontset;
+
+  g_return_val_if_fail (font != NULL, -1);
+  g_return_val_if_fail (text != NULL, -1);
+
+  private = (GdkFontPrivate*) font;
+
+  switch (font->type)
+    {
+    case GDK_FONT_FONT:
+      xfont = (XFontStruct *) private->xfont;
+      if ((xfont->min_byte1 == 0) && (xfont->max_byte1 == 0))
+	{
+	  width = XTextWidth (xfont, text, text_length);
+	}
+      else
+	{
+	  width = XTextWidth16 (xfont, (XChar2b *) text, text_length / 2);
+	}
+      break;
+    case GDK_FONT_FONTSET:
+      fontset = (XFontSet) private->xfont;
+      width = XmbTextEscapement (fontset, text, text_length);
+      break;
+    default:
+      width = 0;
+    }
+  return width;
+}
+
+gint
+gdk_text_width_wc (GdkFont	  *font,
+		   const GdkWChar *text,
+		   gint		   text_length)
+{
+  GdkFontPrivate *private;
+  gint width;
+  XFontSet fontset;
+
+  g_return_val_if_fail (font != NULL, -1);
+  g_return_val_if_fail (text != NULL, -1);
+
+  private = (GdkFontPrivate*) font;
+
+  switch (font->type)
+    {
+    case GDK_FONT_FONT:
+      {
+	gchar *glyphs;
+	int glyphs_len;
+
+	if (_gdk_font_wc_to_glyphs (font, text, text_length,
+				    &glyphs, &glyphs_len))
+	  {
+	    width = gdk_text_width (font, glyphs, glyphs_len);
+	    g_free (glyphs);
+	  }
+	else
+	  width = 0;
+
+	break;
+      }
+    case GDK_FONT_FONTSET:
+      if (sizeof(GdkWChar) == sizeof(wchar_t))
+	{
+	  fontset = (XFontSet) private->xfont;
+	  width = XwcTextEscapement (fontset, (wchar_t *)text, text_length);
+	}
+      else
+	{
+	  wchar_t *text_wchar;
+	  gint i;
+	  fontset = (XFontSet) private->xfont;
+	  text_wchar = g_new(wchar_t, text_length);
+	  for (i=0; i<text_length; i++) text_wchar[i] = text[i];
+	  width = XwcTextEscapement (fontset, text_wchar, text_length);
+	  g_free (text_wchar);
+	}
+      break;
+    default:
+      width = 0;
+    }
+  return width;
+}
+
+/* Problem: What if a character is a 16 bits character ?? */
+gint
+gdk_char_width (GdkFont *font,
+		gchar    character)
+{
+  GdkFontPrivate *private;
+  XCharStruct *chars;
+  gint width;
+  guint ch = character & 0xff;  /* get rid of sign-extension */
+  XFontStruct *xfont;
+  XFontSet fontset;
+
+  g_return_val_if_fail (font != NULL, -1);
+
+  private = (GdkFontPrivate*) font;
+
+  switch (font->type)
+    {
+    case GDK_FONT_FONT:
+      /* only 8 bits characters are considered here */
+      xfont = (XFontStruct *) private->xfont;
+      if ((xfont->min_byte1 == 0) &&
+	  (xfont->max_byte1 == 0) &&
+	  (ch >= xfont->min_char_or_byte2) &&
+	  (ch <= xfont->max_char_or_byte2))
+	{
+	  chars = xfont->per_char;
+	  if (chars)
+	    width = chars[ch - xfont->min_char_or_byte2].width;
+	  else
+	    width = xfont->min_bounds.width;
+	}
+      else
+	{
+	  width = XTextWidth (xfont, &character, 1);
+	}
+      break;
+    case GDK_FONT_FONTSET:
+      fontset = (XFontSet) private->xfont;
+      width = XmbTextEscapement (fontset, &character, 1) ;
+      break;
+    default:
+      width = 0;
+    }
+  return width;
+}
+
+gint
+gdk_char_width_wc (GdkFont *font,
+		   GdkWChar character)
+{
+  GdkFontPrivate *private;
+  gint width;
+  XFontSet fontset;
+
+  g_return_val_if_fail (font != NULL, -1);
+
+  private = (GdkFontPrivate*) font;
+
+  switch (font->type)
+    {
+    case GDK_FONT_FONT:
+#ifdef USE_NATIVE_LOCALE
+      if (MB_CUR_MAX == 1 && FONT_IS_8BIT(private))
+	{
+	  char c;
+	  g_assert (wctomb(&c,character) == 1);
+
+	  return gdk_char_width (font, c);
+	}
+      else
+#endif /* USE_NATIVE_LOCALE */
+	{
+	  gchar *glyphs;
+	  int glyphs_len;
+
+	  if (_gdk_font_wc_to_glyphs (font, &character, 1, &glyphs, &glyphs_len))
+	    {
+	      width = gdk_text_width (font, glyphs, glyphs_len);
+	      g_free (glyphs);
+	    }
+	  else
+	    width = 0;
+	  
+	  break;
+	}
+    case GDK_FONT_FONTSET:
+      fontset = (XFontSet) private->xfont;
+      {
+	wchar_t char_wc = character;
+        width = XwcTextEscapement (fontset, &char_wc, 1) ;
+      }
+      break;
+    default:
+      width = 0;
+    }
+  return width;
+}
+
+gint
+gdk_string_measure (GdkFont     *font,
+                    const gchar *string)
+{
+  g_return_val_if_fail (font != NULL, -1);
+  g_return_val_if_fail (string != NULL, -1);
+
+  return gdk_text_measure (font, string, strlen (string));
+}
+
+void
+gdk_text_extents (GdkFont     *font,
+                  const gchar *text,
+                  gint         text_length,
+		  gint        *lbearing,
+		  gint        *rbearing,
+		  gint        *width,
+		  gint        *ascent,
+		  gint        *descent)
+{
+  GdkFontPrivate *private;
+  XCharStruct overall;
+  XFontStruct *xfont;
+  XFontSet    fontset;
+  XRectangle  ink, logical;
+  int direction;
+  int font_ascent;
+  int font_descent;
+
+  g_return_if_fail (font != NULL);
+  g_return_if_fail (text != NULL);
+
+  private = (GdkFontPrivate*) font;
+
+  switch (font->type)
+    {
+    case GDK_FONT_FONT:
+      xfont = (XFontStruct *) private->xfont;
+      if ((xfont->min_byte1 == 0) && (xfont->max_byte1 == 0))
+	{
+	  XTextExtents (xfont, text, text_length,
+			&direction, &font_ascent, &font_descent,
+			&overall);
+	}
+      else
+	{
+	  XTextExtents16 (xfont, (XChar2b *) text, text_length / 2,
+			  &direction, &font_ascent, &font_descent,
+			  &overall);
+	}
+      if (lbearing)
+	*lbearing = overall.lbearing;
+      if (rbearing)
+	*rbearing = overall.rbearing;
+      if (width)
+	*width = overall.width;
+      if (ascent)
+	*ascent = overall.ascent;
+      if (descent)
+	*descent = overall.descent;
+      break;
+    case GDK_FONT_FONTSET:
+      fontset = (XFontSet) private->xfont;
+      XmbTextExtents (fontset, text, text_length, &ink, &logical);
+      if (lbearing)
+	*lbearing = ink.x;
+      if (rbearing)
+	*rbearing = ink.x + ink.width;
+      if (width)
+	*width = logical.width;
+      if (ascent)
+	*ascent = -ink.y;
+      if (descent)
+	*descent = ink.y + ink.height;
+      break;
+    }
+
+}
+
+void
+gdk_text_extents_wc (GdkFont        *font,
+		     const GdkWChar *text,
+		     gint            text_length,
+		     gint           *lbearing,
+		     gint           *rbearing,
+		     gint           *width,
+		     gint           *ascent,
+		     gint           *descent)
+{
+  GdkFontPrivate *private;
+  XFontSet    fontset;
+  XRectangle  ink, logical;
+
+  g_return_if_fail (font != NULL);
+  g_return_if_fail (text != NULL);
+
+  private = (GdkFontPrivate*) font;
+
+  switch (font->type)
+    {
+    case GDK_FONT_FONT:
+      {
+	gchar *glyphs;
+	int glyphs_len;
+
+	if (_gdk_font_wc_to_glyphs (font, text, text_length,
+				    &glyphs, &glyphs_len))
+	  {
+	    gdk_text_extents (font, glyphs, glyphs_len,
+			      lbearing, rbearing, width, ascent, descent);
+	    g_free (glyphs);
+	  }
+	else
+	  {
+	    if (lbearing)
+	      *lbearing = 0;
+	    if (rbearing)
+	      *rbearing = 0;
+	    if (width)
+	      *width = 0;
+	    if (ascent)
+	      *ascent = 0;
+	    if (descent)
+	      *descent = 0;
+	  }
+
+	break;
+      }
+    case GDK_FONT_FONTSET:
+      fontset = (XFontSet) private->xfont;
+
+      if (sizeof(GdkWChar) == sizeof(wchar_t))
+	XwcTextExtents (fontset, (wchar_t *)text, text_length, &ink, &logical);
+      else
+	{
+	  wchar_t *text_wchar;
+	  gint i;
+	  
+	  text_wchar = g_new (wchar_t, text_length);
+	  for (i = 0; i < text_length; i++)
+	    text_wchar[i] = text[i];
+	  XwcTextExtents (fontset, text_wchar, text_length, &ink, &logical);
+	  g_free (text_wchar);
+	}
+      if (lbearing)
+	*lbearing = ink.x;
+      if (rbearing)
+	*rbearing = ink.x + ink.width;
+      if (width)
+	*width = logical.width;
+      if (ascent)
+	*ascent = -ink.y;
+      if (descent)
+	*descent = ink.y + ink.height;
+      break;
+    }
+
+}
+
+void
+gdk_string_extents (GdkFont     *font,
+		    const gchar *string,
+		    gint        *lbearing,
+		    gint        *rbearing,
+		    gint        *width,
+		    gint        *ascent,
+		    gint        *descent)
+{
+  g_return_if_fail (font != NULL);
+  g_return_if_fail (string != NULL);
+
+  gdk_text_extents (font, string, strlen (string),
+		    lbearing, rbearing, width, ascent, descent);
+}
+
+
+gint
+gdk_text_measure (GdkFont     *font,
+                  const gchar *text,
+                  gint         text_length)
+{
+  GdkFontPrivate *private;
+  XCharStruct overall;
+  XFontStruct *xfont;
+  XFontSet    fontset;
+  XRectangle  ink, log;
+  int direction;
+  int font_ascent;
+  int font_descent;
+  gint width;
+
+  g_return_val_if_fail (font != NULL, -1);
+  g_return_val_if_fail (text != NULL, -1);
+
+  private = (GdkFontPrivate*) font;
+
+  switch (font->type)
+    {
+    case GDK_FONT_FONT:
+      xfont = (XFontStruct *) private->xfont;
+      if ((xfont->min_byte1 == 0) && (xfont->max_byte1 == 0))
+	{
+	  XTextExtents (xfont, text, text_length,
+			&direction, &font_ascent, &font_descent,
+			&overall);
+	}
+      else
+	{
+	  XTextExtents16 (xfont, (XChar2b *) text, text_length / 2,
+			  &direction, &font_ascent, &font_descent,
+			  &overall);
+	}
+      width = overall.rbearing;
+      break;
+    case GDK_FONT_FONTSET:
+      fontset = (XFontSet) private->xfont;
+      XmbTextExtents (fontset, text, text_length, &ink, &log);
+      width = ink.x + ink.width;
+      break;
+    default:
+      width = 0;
+    }
+  return width;
+}
+
+gint
+gdk_char_measure (GdkFont *font,
+                  gchar    character)
+{
+  g_return_val_if_fail (font != NULL, -1);
+
+  return gdk_text_measure (font, &character, 1);
+}
+
+gint
+gdk_string_height (GdkFont     *font,
+		   const gchar *string)
+{
+  g_return_val_if_fail (font != NULL, -1);
+  g_return_val_if_fail (string != NULL, -1);
+
+  return gdk_text_height (font, string, strlen (string));
+}
+
+gint
+gdk_text_height (GdkFont     *font,
+		 const gchar *text,
+		 gint         text_length)
+{
+  GdkFontPrivate *private;
+  XCharStruct overall;
+  XFontStruct *xfont;
+  XFontSet    fontset;
+  XRectangle  ink, log;
+  int direction;
+  int font_ascent;
+  int font_descent;
+  gint height;
+
+  g_return_val_if_fail (font != NULL, -1);
+  g_return_val_if_fail (text != NULL, -1);
+
+  private = (GdkFontPrivate*) font;
+
+  switch (font->type)
+    {
+    case GDK_FONT_FONT:
+      xfont = (XFontStruct *) private->xfont;
+      if ((xfont->min_byte1 == 0) && (xfont->max_byte1 == 0))
+	{
+	  XTextExtents (xfont, text, text_length,
+			&direction, &font_ascent, &font_descent,
+			&overall);
+	}
+      else
+	{
+	  XTextExtents16 (xfont, (XChar2b *) text, text_length / 2,
+			  &direction, &font_ascent, &font_descent,
+			  &overall);
+	}
+      height = overall.ascent + overall.descent;
+      break;
+    case GDK_FONT_FONTSET:
+      fontset = (XFontSet) private->xfont;
+      XmbTextExtents (fontset, text, text_length, &ink, &log);
+      height = log.height;
+      break;
+    default:
+      height = 0;
+    }
+  return height;
+}
+
+gint
+gdk_char_height (GdkFont *font,
+		 gchar    character)
+{
+  g_return_val_if_fail (font != NULL, -1);
+
+  return gdk_text_height (font, &character, 1);
+}
+
+gboolean
+_gdk_font_wc_to_glyphs (GdkFont        *font,
+			const GdkWChar *text,
+			gint            text_length,
+			gchar         **result,
+			gint           *result_length)
+{
+  XFontStruct *xfont;
+  GdkFontPrivate *font_private = (GdkFontPrivate*) font;
+
+  g_return_val_if_fail (font != NULL, FALSE);
+  g_return_val_if_fail (font->type == GDK_FONT_FONT, FALSE);
+
+  xfont = (XFontStruct *) font_private->xfont;
+
+  if (FONT_IS_8BIT (font_private))
+    {
+      /* 8-bit font, assume that we are in a 8-bit locale,
+       * and convert to bytes using wcstombs.
+       */
+      char *mbstr = _gdk_wcstombs_len (text, text_length);
+
+      if (result_length)
+	*result_length = mbstr ? strlen (mbstr) : 0;
+
+      if (result)
+	*result = mbstr;
+      else
+	g_free (mbstr);
+
+      return mbstr != NULL;
+    }
+  else
+    {
+      /* 16-bit font. Who knows what was intended? Make a random
+       * guess.
+       */
+      XChar2b *result2b = g_new (XChar2b, text_length + 1);
+      gint i;
+
+      for (i = 0; i < text_length; i++)
+	{
+	  result2b[i].byte1 = text[i] / 256;
+	  result2b[i].byte2 = text[i] % 256;
+	}
+
+      result2b[i].byte1 = result2b[i].byte2 = 0;
+
+      if (result)
+	*result = (gchar *)result2b;
+
+      if (result_length)
+	*result_length = text_length;
+
+      return TRUE;
+    }
+}
diff -ruN gtk+-1.2.10/gdk/gdki18n.h gtk-n/gdk/gdki18n.h
--- gtk+-1.2.10/gdk/gdki18n.h	Mon Jan 24 03:58:21 2000
+++ gtk-n/gdk/gdki18n.h	Thu Jan 31 08:56:46 2002
@@ -51,4 +51,32 @@
 #  define gdk_iswspace(c) ((wchar_t)(c) <= 0xFF && isspace(c))
 #endif
 
+/* The following 9 macros are added in gtk+ 1.2.X. Don't use them without
+ * checking GTK_CHECK_VERSION. For example,
+ *	#if GTK_CHECK_VERSION (1,2,X)
+ *	    ... code which uses gdk_iswalpha(), gdk_iswcntrl(), etc. ...
+ *      #endif
+ */
+#if !defined(G_HAVE_BROKEN_WCTYPE) && (defined(G_HAVE_WCTYPE_H) || defined(G_HAVE_WCHAR_H)) && !defined(X_LOCALE)
+#  define gdk_iswalpha(c)  iswalpha(c)
+#  define gdk_iswcntrl(c)  iswcntrl(c)
+#  define gdk_iswdigit(c)  iswdigit(c)
+#  define gdk_iswlower(c)  iswlower(c)
+#  define gdk_iswgraph(c)  iswgraph(c)
+#  define gdk_iswprint(c)  iswprint(c)
+#  define gdk_iswpunct(c)  iswpunct(c)
+#  define gdk_iswupper(c)  iswupper(c)
+#  define gdk_iswxdigit(c) iswxdigit(c)
+#else
+#  define gdk_iswalpha(c)  ((wchar_t)(c) <= 0xFF && isalpha(c))
+#  define gdk_iswcntrl(c)  ((wchar_t)(c) <= 0xFF && iscntrl(c))
+#  define gdk_iswdigit(c)  ((wchar_t)(c) <= 0xFF && isdigit(c))
+#  define gdk_iswlower(c)  ((wchar_t)(c) <= 0xFF && islower(c))
+#  define gdk_iswgraph(c)  ((wchar_t)(c) >  0xFF || isgraph(c))
+#  define gdk_iswprint(c)  ((wchar_t)(c) >  0xFF || isprint(c))
+#  define gdk_iswpunct(c)  ((wchar_t)(c) <= 0xFF && ispunct(c))
+#  define gdk_iswupper(c)  ((wchar_t)(c) <= 0xFF && isupper(c))
+#  define gdk_iswxdigit(c) ((wchar_t)(c) <= 0xFF && isxdigit(c))
+#endif
+
 #endif /* __GDK_I18N_H__ */
diff -ruN gtk+-1.2.10/gdk/gdki18n.h.orig gtk-n/gdk/gdki18n.h.orig
--- gtk+-1.2.10/gdk/gdki18n.h.orig	Thu Jan  1 01:00:00 1970
+++ gtk-n/gdk/gdki18n.h.orig	Mon Jan 24 03:58:21 2000
@@ -0,0 +1,54 @@
+/* GDK - The GIMP Drawing Kit
+ * 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 Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-1999.  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 __GDK_I18N_H__
+#define __GDK_I18N_H__
+
+/* GDK uses "glib". (And so does GTK).
+ */
+#include <glib.h>
+
+/* international string support */
+
+#include <stdlib.h>
+
+#if !defined(G_HAVE_BROKEN_WCTYPE) && (defined(G_HAVE_WCTYPE_H) || defined(G_HAVE_WCHAR_H)) && !defined(X_LOCALE)
+#  ifdef G_HAVE_WCTYPE_H
+#    include <wctype.h>
+#  else
+#    ifdef G_HAVE_WCHAR_H
+#      include <wchar.h>
+#    endif
+#  endif
+#  define gdk_iswalnum(c) iswalnum(c)
+#  define gdk_iswspace(c) iswspace(c)
+#else
+#  include <ctype.h>
+#  define gdk_iswalnum(c) ((wchar_t)(c) <= 0xFF && isalnum(c))
+#  define gdk_iswspace(c) ((wchar_t)(c) <= 0xFF && isspace(c))
+#endif
+
+#endif /* __GDK_I18N_H__ */
diff -ruN gtk+-1.2.10/gdk/gdkselection.c gtk-n/gdk/gdkselection.c
--- gtk+-1.2.10/gdk/gdkselection.c	Thu Mar 15 20:09:36 2001
+++ gtk-n/gdk/gdkselection.c	Thu Jan 31 08:56:28 2002
@@ -191,73 +191,6 @@
   gdk_send_xevent (requestor, False, NoEventMask, (XEvent*) &xevent);
 }
 
-
-/* The output of XmbTextPropertyToTextList may include stuff not valid
- * for COMPOUND_TEXT. This routine tries to correct this by:
- *
- * a) Canonicalizing CR LF and CR to LF
- * b) Stripping out all other non-allowed control characters
- *
- * See the COMPOUND_TEXT spec distributed with X for explanations
- * what is allowed.
- */
-static gchar *
-sanitize_ctext (const char *str,
-		gint       *length)
-{
-  gchar *result = g_malloc (*length + 1);
-  gint out_length = 0;
-  gint i;
-  const guchar *ustr = (const guchar *)str;
-
-  for (i=0; i < *length; i++)
-    {
-      guchar c = ustr[i];
-      
-      if (c == '\r')
-	{
-	  result[out_length++] = '\n';
-	  if (i + 1 < *length && ustr[i + 1] == '\n')
-	    i++;
-	}
-      else if (c == 27 /* ESC */)
-	{
-	  /* Check for "extended segments, which can contain arbitrary
-	   * octets. See CTEXT spec, section 6.
-	   */
-
-	  if (i + 5 < *length &&
-	      ustr[i + 1] == '%' &&
-	      ustr[i + 2] == '/' &&
-	      (ustr[i + 3] >= 48 && ustr[i + 3] <= 52) &&
-	      ustr[i + 4] >= 128 &&
-	      ustr[i + 5] >= 128)
-	    {
-	      int extra_len = 6 + (ustr[i + 4] - 128) * 128 + ustr[i + 5] - 128;
-	      extra_len = MAX (extra_len, *length - i);
-
-	      memcpy (result + out_length, ustr + i, extra_len);
-	      out_length += extra_len;
-	      i += extra_len - 1;
-	    }
-	  else
-	    result[out_length++] = c;	    
-	}
-      else if (c == '\n' || c == '\t' || c == 27 /* ESC */ ||
-	       (c >= 32 && c <= 127) ||	/* GL */
-	       c == 155 /* CONTROL SEQUENCE INTRODUCER */ ||	
-	       (c >= 160 && c <= 255)) /* GR */
-	{
-	  result[out_length++] = c;
-	}
-    }
-
-  result[out_length] = '\0';
-  *length = out_length;
-  
-  return result;
-}
-
 gint
 gdk_text_property_to_text_list (GdkAtom encoding, gint format, 
 				guchar *text, gint length,
@@ -266,32 +199,16 @@
   XTextProperty property;
   gint count = 0;
   gint res;
-  gchar *sanitized_text = NULL;
 
   if (!list) 
     return 0;
 
   property.encoding = encoding;
   property.format = format;
-
-  if (encoding == gdk_atom_intern ("COMPOUND_TEXT", FALSE) && format == 8)
-    {
-      gint sanitized_text_length = length;
-      
-      property.value = sanitized_text = sanitize_ctext (text, &sanitized_text_length);
-      property.nitems = sanitized_text_length;
-    }
-  else
-    {
-      property.value = text;
-      property.nitems = length;
-    }
-  
+  property.value = text;
+  property.nitems = length;
   res = XmbTextPropertyToTextList (GDK_DISPLAY(), &property, list, &count);
 
-  if (sanitized_text)
-    g_free (sanitized_text);
-
   if (res == XNoMemory || res == XLocaleNotSupported || 
       res == XConverterNotFound)
     return 0;
@@ -314,8 +231,6 @@
 {
   gint res;
   XTextProperty property;
-  gint sanitized_text_length;
-  gchar *sanitized_text;
 
   res = XmbTextListToTextProperty (GDK_DISPLAY(), 
 				   (char **)&str, 1, XCompoundTextStyle,
@@ -334,17 +249,10 @@
     *encoding = property.encoding;
   if (format)
     *format = property.format;
-
-  sanitized_text_length = property.nitems;
-  sanitized_text = sanitize_ctext (property.value, &sanitized_text_length);
-
   if (ctext)
-    *ctext = sanitized_text;
-  else
-    g_free (sanitized_text);
-  
+    *ctext = g_strdup (property.value);
   if (length)
-    *length = sanitized_text_length;
+    *length = property.nitems;
 
   if (property.value)
     XFree (property.value);
diff -ruN gtk+-1.2.10/gtk/Makefile.am gtk-n/gtk/Makefile.am
--- gtk+-1.2.10/gtk/Makefile.am	Fri Feb  2 18:09:02 2001
+++ gtk-n/gtk/Makefile.am	Thu Jan 31 08:56:58 2002
@@ -374,10 +374,12 @@
 
 
 gtkconfdir = $(sysconfdir)/gtk
-gtkconf_DATA = gtkrc.az gtkrc.el gtkrc.eo gtkrc.he gtkrc.hy gtkrc.ja \
-	gtkrc.ko gtkrc.ru gtkrc.tr gtkrc.th gtkrc.uk gtkrc.iso-8859-2 \
-	gtkrc.iso-8859-5 gtkrc.iso-8859-13 gtkrc.iso-8859-14 \
-	gtkrc.iso-8859-15 gtkrc.zh_CN gtkrc.zh_TW.big5 \
+gtkconf_DATA = gtkrc.az gtkrc.he gtkrc.hy gtkrc.ja \
+	gtkrc.ko gtkrc.ru gtkrc.th gtkrc.uk \
+	gtkrc.utf8 gtkrc.iso88592 \
+	gtkrc.iso88593 gtkrc.iso88595 gtkrc.iso88597 \
+	gtkrc.iso88599 gtkrc.iso885913 gtkrc.iso885914 \
+	gtkrc.iso885915 gtkrc.zh_CN gtkrc.zh_TW.big5 \
 	gtkrc.ka_GE.georgianacademy gtkrc.ka_GE.georgianps \
 	gtkrc.vi_VN.tcvn gtkrc.vi_VN.viscii gtkrc.cp1251 gtkrc.cp1255
 
@@ -390,11 +392,11 @@
 	cd $(DESTDIR)$(gtkconfdir) && \
 	  for i in cs hr hu pl ro sk sl sq sr ; do \
 	    rm -f gtkrc.$$i ; \
-	    ln -s gtkrc.iso-8859-2 gtkrc.$$i ; \
+	    ln -s gtkrc.iso88592 gtkrc.$$i ; \
 	  done ; \
 	  for i in bg_BG.iso88595 mk sp ru_RU.iso88595 ; do \
 	    rm -f gtkrc.$$i ; \
-	    ln -s gtkrc.iso-8859-5 gtkrc.$$i ; \
+	    ln -s gtkrc.iso88595 gtkrc.$$i ; \
 	  done ; \
 	  for i in he_IL.cp1255 he_IL.microsoftcp1255 yi ; do \
 	    rm -f gtkrc.$$i ; \
@@ -403,12 +405,12 @@
 	rm -f gtkrc.lt gtkrc.lv gtkrc.cy gtkrc.ga gtkrc.et gtkrc.ka \
 	     gtkrc.vi_VN.viscii111 gtkrc.vi_VN.tcvn5712 gtkrc.vi \
 	     gtkrc.be gtkrc.bg gtkrc.mi ; \
-	ln -s gtkrc.iso-8859-13 gtkrc.mi ; \
-	ln -s gtkrc.iso-8859-13 gtkrc.lt ; \
-	ln -s gtkrc.iso-8859-13 gtkrc.lv ; \
-	ln -s gtkrc.iso-8859-14 gtkrc.cy ; \
-	ln -s gtkrc.iso-8859-14 gtkrc.ga ; \
-	ln -s gtkrc.iso-8859-15 gtkrc.et ; \
+	ln -s gtkrc.iso885913 gtkrc.mi ; \
+	ln -s gtkrc.iso885913 gtkrc.lt ; \
+	ln -s gtkrc.iso885913 gtkrc.lv ; \
+	ln -s gtkrc.iso885914 gtkrc.cy ; \
+	ln -s gtkrc.iso885914 gtkrc.ga ; \
+	ln -s gtkrc.iso885915 gtkrc.et ; \
 	ln -s gtkrc.ka_GE.georgianps gtkrc.ka ; \
 	ln -s gtkrc.vi_VN.viscii gtkrc.vi_VN.viscii111 ; \
 	ln -s gtkrc.vi_VN.tcvn gtkrc.vi ; \
diff -ruN gtk+-1.2.10/gtk/gtkentry.c gtk-n/gtk/gtkentry.c
--- gtk+-1.2.10/gtk/gtkentry.c	Mon Apr  2 04:14:54 2001
+++ gtk-n/gtk/gtkentry.c	Thu Jan 31 08:57:05 2002
@@ -1184,6 +1184,7 @@
 	}
       break;
     case GDK_Return:
+    case GDK_KP_Enter:
       return_val = TRUE;
       gtk_widget_activate (widget);
       break;
@@ -2036,11 +2037,21 @@
     }
 }
 
+static gboolean
+alnum_or_ideogram (GtkEntry *entry, guint index)
+{
+  GdkWChar ch;
+  ch = entry->text[index];
+  if (entry->use_wchar)
+    return !(gdk_iswpunct (ch) || gdk_iswcntrl (ch) || gdk_iswspace (ch));
+  else
+    return !(ispunct (ch) || iscntrl (ch) || isspace (ch));
+}
+
 static void
 gtk_move_forward_word (GtkEntry *entry)
 {
   GtkEditable *editable;
-  GdkWChar *text;
   gint i;
 
   editable = GTK_EDITABLE (entry);
@@ -2054,21 +2065,12 @@
 
   if (entry->text && (editable->current_pos < entry->text_length))
     {
-      text = entry->text;
-      i = editable->current_pos;
-	  
-      if ((entry->use_wchar) ? (!gdk_iswalnum (text[i])) : (!isalnum (text[i])))
-	for (; i < entry->text_length; i++)
-	  {
-	    if ((entry->use_wchar) ? gdk_iswalnum (text[i]) : isalnum (text[i]))
-	      break;
-	  }
-
+      for (i = editable->current_pos; i < entry->text_length; i++)
+	if (alnum_or_ideogram (entry, i))
+	  break;
       for (; i < entry->text_length; i++)
-	{
-	  if ((entry->use_wchar) ? (!gdk_iswalnum (text[i])) : (!isalnum (text[i])))
-	    break;
-	}
+	if (!alnum_or_ideogram (entry, i))
+	  break;
 
       editable->current_pos = i;
     }
@@ -2078,7 +2080,6 @@
 gtk_move_backward_word (GtkEntry *entry)
 {
   GtkEditable *editable;
-  GdkWChar *text;
   gint i;
 
   editable = GTK_EDITABLE (entry);
@@ -2092,26 +2093,19 @@
 
   if (entry->text && editable->current_pos > 0)
     {
-      text = entry->text;
-      i = editable->current_pos - 1;
-      if ((entry->use_wchar) ? (!gdk_iswalnum (text[i])) : (!isalnum (text[i])))
-	for (; i >= 0; i--)
+      for (i = editable->current_pos - 1; i >= 0; i--)
+	if (alnum_or_ideogram (entry, i))
+	  break;
+      for (; i >= 0; i--)
+	if (!alnum_or_ideogram (entry, i))
 	  {
-	    if ((entry->use_wchar) ? gdk_iswalnum (text[i]) : isalnum (text[i]))
-	      break;
+	    i++;
+	    break;
 	  }
-      for (; i >= 0; i--)
-	{
-	  if ((entry->use_wchar) ? (!gdk_iswalnum (text[i])) : (!isalnum (text[i])))
-	    {
-	      i++;
-	      break;
-	    }
-	}
-	  
+
       if (i < 0)
 	i = 0;
-	  
+  
       editable->current_pos = i;
     }
 }
diff -ruN gtk+-1.2.10/gtk/gtkentry.c.orig gtk-n/gtk/gtkentry.c.orig
--- gtk+-1.2.10/gtk/gtkentry.c.orig	Thu Jan  1 01:00:00 1970
+++ gtk-n/gtk/gtkentry.c.orig	Mon Apr  2 04:14:54 2001
@@ -0,0 +1,2408 @@
+/* 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 Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-1999.  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/. 
+ */
+
+#include <ctype.h>
+#include <string.h>
+#include "gdk/gdkkeysyms.h"
+#include "gdk/gdki18n.h"
+#include "gtkentry.h"
+#include "gtkmain.h"
+#include "gtkselection.h"
+#include "gtksignal.h"
+#include "gtkstyle.h"
+
+#define MIN_ENTRY_WIDTH  150
+#define DRAW_TIMEOUT     20
+
+/* If you are going to change this, see the note in entry_adjust_scroll */
+#define INNER_BORDER     2
+
+enum {
+  ARG_0,
+  ARG_MAX_LENGTH,
+  ARG_VISIBILITY
+};
+
+
+static void gtk_entry_class_init          (GtkEntryClass     *klass);
+static void gtk_entry_init                (GtkEntry          *entry);
+static void gtk_entry_set_arg      	  (GtkObject         *object,
+					   GtkArg            *arg,
+					   guint              arg_id);
+static void gtk_entry_get_arg		  (GtkObject         *object,
+					   GtkArg            *arg,
+					   guint              arg_id);
+static void gtk_entry_finalize            (GtkObject         *object);
+static void gtk_entry_realize             (GtkWidget         *widget);
+static void gtk_entry_unrealize           (GtkWidget         *widget);
+static void gtk_entry_draw_focus          (GtkWidget         *widget);
+static void gtk_entry_size_request        (GtkWidget         *widget,
+					   GtkRequisition    *requisition);
+static void gtk_entry_size_allocate       (GtkWidget         *widget,
+					   GtkAllocation     *allocation);
+static void gtk_entry_make_backing_pixmap (GtkEntry *entry,
+					   gint width, gint height);
+static void gtk_entry_draw                (GtkWidget         *widget,
+					   GdkRectangle      *area);
+static gint gtk_entry_expose              (GtkWidget         *widget,
+					   GdkEventExpose    *event);
+static gint gtk_entry_button_press        (GtkWidget         *widget,
+					   GdkEventButton    *event);
+static gint gtk_entry_button_release      (GtkWidget         *widget,
+					   GdkEventButton    *event);
+static gint gtk_entry_motion_notify       (GtkWidget         *widget,
+					   GdkEventMotion    *event);
+static gint gtk_entry_key_press           (GtkWidget         *widget,
+					   GdkEventKey       *event);
+static gint gtk_entry_focus_in            (GtkWidget         *widget,
+					   GdkEventFocus     *event);
+static gint gtk_entry_focus_out           (GtkWidget         *widget,
+					   GdkEventFocus     *event);
+static void gtk_entry_draw_text           (GtkEntry          *entry);
+static void gtk_entry_draw_cursor         (GtkEntry          *entry);
+static void gtk_entry_draw_cursor_on_drawable
+					  (GtkEntry          *entry,
+					   GdkDrawable       *drawable);
+static void gtk_entry_style_set	          (GtkWidget         *widget,
+					   GtkStyle          *previous_style);
+static void gtk_entry_state_changed	  (GtkWidget         *widget,
+					   GtkStateType       previous_state);
+#ifdef USE_XIM
+static void gtk_entry_update_ic_attr      (GtkWidget         *widget);
+#endif
+static void gtk_entry_queue_draw          (GtkEntry          *entry);
+static gint gtk_entry_timer               (gpointer           data);
+static gint gtk_entry_position            (GtkEntry          *entry,
+					   gint               x);
+static void entry_adjust_scroll           (GtkEntry          *entry);
+static void gtk_entry_grow_text           (GtkEntry          *entry);
+static void gtk_entry_insert_text         (GtkEditable       *editable,
+					   const gchar       *new_text,
+					   gint               new_text_length,
+					   gint              *position);
+static void gtk_entry_delete_text         (GtkEditable       *editable,
+					   gint               start_pos,
+					   gint               end_pos);
+static void gtk_entry_update_text         (GtkEditable       *editable,
+					   gint               start_pos,
+					   gint               end_pos);
+static gchar *gtk_entry_get_chars         (GtkEditable       *editable,
+					   gint               start_pos,
+					   gint               end_pos);
+
+/* Binding actions */
+static void gtk_entry_move_cursor         (GtkEditable *editable,
+					   gint         x,
+					   gint         y);
+static void gtk_entry_move_word           (GtkEditable *editable,
+					   gint         n);
+static void gtk_entry_move_to_column      (GtkEditable *editable,
+					   gint         row);
+static void gtk_entry_kill_char           (GtkEditable *editable,
+					   gint         direction);
+static void gtk_entry_kill_word           (GtkEditable *editable,
+					   gint         direction);
+static void gtk_entry_kill_line           (GtkEditable *editable,
+					   gint         direction);
+
+/* To be removed */
+static void gtk_move_forward_character    (GtkEntry          *entry);
+static void gtk_move_backward_character   (GtkEntry          *entry);
+static void gtk_move_forward_word         (GtkEntry          *entry);
+static void gtk_move_backward_word        (GtkEntry          *entry);
+static void gtk_move_beginning_of_line    (GtkEntry          *entry);
+static void gtk_move_end_of_line          (GtkEntry          *entry);
+static void gtk_delete_forward_character  (GtkEntry          *entry);
+static void gtk_delete_backward_character (GtkEntry          *entry);
+static void gtk_delete_forward_word       (GtkEntry          *entry);
+static void gtk_delete_backward_word      (GtkEntry          *entry);
+static void gtk_delete_line               (GtkEntry          *entry);
+static void gtk_delete_to_line_end        (GtkEntry          *entry);
+static void gtk_select_word               (GtkEntry          *entry,
+					   guint32            time);
+static void gtk_select_line               (GtkEntry          *entry,
+					   guint32            time);
+
+
+static void gtk_entry_set_selection       (GtkEditable       *editable,
+					   gint               start,
+					   gint               end);
+
+static void gtk_entry_recompute_offsets   (GtkEntry          *entry);
+static gint gtk_entry_find_position       (GtkEntry          *entry, 
+					   gint               position);
+static void gtk_entry_set_position_from_editable (GtkEditable *editable,
+						  gint         position);
+
+static GtkWidgetClass *parent_class = NULL;
+static GdkAtom ctext_atom = GDK_NONE;
+
+static const GtkTextFunction control_keys[26] =
+{
+  (GtkTextFunction)gtk_move_beginning_of_line,    /* a */
+  (GtkTextFunction)gtk_move_backward_character,   /* b */
+  (GtkTextFunction)gtk_editable_copy_clipboard,   /* c */
+  (GtkTextFunction)gtk_delete_forward_character,  /* d */
+  (GtkTextFunction)gtk_move_end_of_line,          /* e */
+  (GtkTextFunction)gtk_move_forward_character,    /* f */
+  NULL,                                           /* g */
+  (GtkTextFunction)gtk_delete_backward_character, /* h */
+  NULL,                                           /* i */
+  NULL,                                           /* j */
+  (GtkTextFunction)gtk_delete_to_line_end,        /* k */
+  NULL,                                           /* l */
+  NULL,                                           /* m */
+  NULL,                                           /* n */
+  NULL,                                           /* o */
+  NULL,                                           /* p */
+  NULL,                                           /* q */
+  NULL,                                           /* r */
+  NULL,                                           /* s */
+  NULL,                                           /* t */
+  (GtkTextFunction)gtk_delete_line,               /* u */
+  (GtkTextFunction)gtk_editable_paste_clipboard,  /* v */
+  (GtkTextFunction)gtk_delete_backward_word,      /* w */
+  (GtkTextFunction)gtk_editable_cut_clipboard,    /* x */
+  NULL,                                           /* y */
+  NULL,                                           /* z */
+};
+
+static const GtkTextFunction alt_keys[26] =
+{
+  NULL,                                           /* a */
+  (GtkTextFunction)gtk_move_backward_word,        /* b */
+  NULL,                                           /* c */
+  (GtkTextFunction)gtk_delete_forward_word,       /* d */
+  NULL,                                           /* e */
+  (GtkTextFunction)gtk_move_forward_word,         /* f */
+  NULL,                                           /* g */
+  NULL,                                           /* h */
+  NULL,                                           /* i */
+  NULL,                                           /* j */
+  NULL,                                           /* k */
+  NULL,                                           /* l */
+  NULL,                                           /* m */
+  NULL,                                           /* n */
+  NULL,                                           /* o */
+  NULL,                                           /* p */
+  NULL,                                           /* q */
+  NULL,                                           /* r */
+  NULL,                                           /* s */
+  NULL,                                           /* t */
+  NULL,                                           /* u */
+  NULL,                                           /* v */
+  NULL,                                           /* w */
+  NULL,                                           /* x */
+  NULL,                                           /* y */
+  NULL,                                           /* z */
+};
+
+
+GtkType
+gtk_entry_get_type (void)
+{
+  static GtkType entry_type = 0;
+
+  if (!entry_type)
+    {
+      static const GtkTypeInfo entry_info =
+      {
+	"GtkEntry",
+	sizeof (GtkEntry),
+	sizeof (GtkEntryClass),
+	(GtkClassInitFunc) gtk_entry_class_init,
+	(GtkObjectInitFunc) gtk_entry_init,
+	/* reserved_1 */ NULL,
+	/* reserved_2 */ NULL,
+        (GtkClassInitFunc) NULL,
+      };
+
+      entry_type = gtk_type_unique (GTK_TYPE_EDITABLE, &entry_info);
+    }
+
+  return entry_type;
+}
+
+static void
+gtk_entry_class_init (GtkEntryClass *class)
+{
+  GtkObjectClass *object_class;
+  GtkWidgetClass *widget_class;
+  GtkEditableClass *editable_class;
+
+  object_class = (GtkObjectClass*) class;
+  widget_class = (GtkWidgetClass*) class;
+  editable_class = (GtkEditableClass*) class;
+  parent_class = gtk_type_class (GTK_TYPE_EDITABLE);
+
+  gtk_object_add_arg_type ("GtkEntry::max_length", GTK_TYPE_UINT, GTK_ARG_READWRITE, ARG_MAX_LENGTH);
+  gtk_object_add_arg_type ("GtkEntry::visibility", GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_VISIBILITY);
+
+  object_class->set_arg = gtk_entry_set_arg;
+  object_class->get_arg = gtk_entry_get_arg;
+  object_class->finalize = gtk_entry_finalize;
+
+  widget_class->realize = gtk_entry_realize;
+  widget_class->unrealize = gtk_entry_unrealize;
+  widget_class->draw_focus = gtk_entry_draw_focus;
+  widget_class->size_request = gtk_entry_size_request;
+  widget_class->size_allocate = gtk_entry_size_allocate;
+  widget_class->draw = gtk_entry_draw;
+  widget_class->expose_event = gtk_entry_expose;
+  widget_class->button_press_event = gtk_entry_button_press;
+  widget_class->button_release_event = gtk_entry_button_release;
+  widget_class->motion_notify_event = gtk_entry_motion_notify;
+  widget_class->key_press_event = gtk_entry_key_press;
+  widget_class->focus_in_event = gtk_entry_focus_in;
+  widget_class->focus_out_event = gtk_entry_focus_out;
+  widget_class->style_set = gtk_entry_style_set;
+  widget_class->state_changed = gtk_entry_state_changed;
+
+  editable_class->insert_text = gtk_entry_insert_text;
+  editable_class->delete_text = gtk_entry_delete_text;
+  editable_class->changed = (void (*)(GtkEditable *)) entry_adjust_scroll;
+
+  editable_class->move_cursor = gtk_entry_move_cursor;
+  editable_class->move_word = gtk_entry_move_word;
+  editable_class->move_to_column = gtk_entry_move_to_column;
+
+  editable_class->kill_char = gtk_entry_kill_char;
+  editable_class->kill_word = gtk_entry_kill_word;
+  editable_class->kill_line = gtk_entry_kill_line;
+
+  editable_class->update_text = gtk_entry_update_text;
+  editable_class->get_chars   = gtk_entry_get_chars;
+  editable_class->set_selection = gtk_entry_set_selection;
+  editable_class->set_position = gtk_entry_set_position_from_editable;
+}
+
+static void
+gtk_entry_set_arg (GtkObject      *object,
+		   GtkArg         *arg,
+		   guint           arg_id)
+{
+  GtkEntry *entry;
+
+  entry = GTK_ENTRY (object);
+
+  switch (arg_id)
+    {
+    case ARG_MAX_LENGTH:
+      gtk_entry_set_max_length (entry, GTK_VALUE_UINT (*arg));
+      break;
+    case ARG_VISIBILITY:
+      gtk_entry_set_visibility (entry, GTK_VALUE_BOOL (*arg));
+      break;
+    default:
+      break;
+    }
+}
+
+static void
+gtk_entry_get_arg (GtkObject      *object,
+		   GtkArg         *arg,
+		   guint           arg_id)
+{
+  GtkEntry *entry;
+
+  entry = GTK_ENTRY (object);
+
+  switch (arg_id)
+    {
+    case ARG_MAX_LENGTH:
+      GTK_VALUE_UINT (*arg) = entry->text_max_length;
+      break;
+    case ARG_VISIBILITY:
+      GTK_VALUE_BOOL (*arg) = GTK_EDITABLE (entry)->visible;
+      break;
+    default:
+      arg->type = GTK_TYPE_INVALID;
+      break;
+    }
+}
+
+static void
+gtk_entry_init (GtkEntry *entry)
+{
+  GTK_WIDGET_SET_FLAGS (entry, GTK_CAN_FOCUS);
+
+  entry->text_area = NULL;
+  entry->backing_pixmap = NULL;
+  entry->text = NULL;
+  entry->text_size = 0;
+  entry->text_length = 0;
+  entry->text_max_length = 0;
+  entry->scroll_offset = 0;
+  entry->timer = 0;
+  entry->button = 0;
+  entry->visible = 1;
+
+  entry->char_offset = NULL;
+  entry->text_mb = NULL;
+  entry->text_mb_dirty = TRUE;
+  entry->use_wchar = FALSE;
+
+  gtk_entry_grow_text (entry);
+}
+
+GtkWidget*
+gtk_entry_new (void)
+{
+  return GTK_WIDGET (gtk_type_new (GTK_TYPE_ENTRY));
+}
+
+static GdkWChar
+gtk_entry_get_invisible_char (GtkEntry *entry)
+{
+  GdkWChar ch = 0;
+
+  if (entry->use_wchar)
+    gdk_mbstowcs (&ch, "*", 1);
+  else
+    ch = '*';
+
+  return ch;
+}
+
+/*
+ * Draws the string, noting that if entry->use_wchar is false, then
+ * the text is not really wide characters, but narrow characters
+ * stored as wide characters.
+ */
+static void
+gtk_entry_draw_wchars (GtkEntry       *entry,
+		       GdkDrawable    *drawable,
+		       GdkFont	      *font,
+		       GdkGC	      *gc,
+		       gint	       x,
+		       gint	       y,
+		       const GdkWChar *text,
+		       gint	       text_length)
+{
+  if (entry->use_wchar)
+    gdk_draw_text_wc (drawable, font, gc, x, y, text, text_length);
+  else
+    {
+      gint i;
+      gchar *mbstr = g_new (gchar, text_length);
+      
+      for (i = 0; i < text_length; i++)
+        mbstr[i] = text[i];
+      gdk_draw_text (drawable, font, gc, x, y, mbstr, text_length);
+      g_free(mbstr);
+    }
+}
+
+GtkWidget*
+gtk_entry_new_with_max_length (guint16 max)
+{
+  GtkEntry *entry;
+
+  entry = gtk_type_new (GTK_TYPE_ENTRY);
+  entry->text_max_length = max;
+
+  return GTK_WIDGET (entry);
+}
+
+void
+gtk_entry_set_text (GtkEntry *entry,
+		    const gchar *text)
+{
+  gint tmp_pos;
+
+  GtkEditable *editable;
+
+  g_return_if_fail (entry != NULL);
+  g_return_if_fail (GTK_IS_ENTRY (entry));
+  g_return_if_fail (text != NULL);
+
+  editable = GTK_EDITABLE (entry);
+  
+  gtk_entry_delete_text (GTK_EDITABLE(entry), 0, entry->text_length);
+
+  tmp_pos = 0;
+  gtk_editable_insert_text (editable, text, strlen (text), &tmp_pos);
+  editable->current_pos = tmp_pos;
+
+  editable->selection_start_pos = 0;
+  editable->selection_end_pos = 0;
+
+  if (GTK_WIDGET_DRAWABLE (entry))
+    gtk_entry_draw_text (entry);
+}
+
+void
+gtk_entry_append_text (GtkEntry *entry,
+		       const gchar *text)
+{
+  gint tmp_pos;
+
+  g_return_if_fail (entry != NULL);
+  g_return_if_fail (GTK_IS_ENTRY (entry));
+  g_return_if_fail (text != NULL);
+
+  tmp_pos = entry->text_length;
+  gtk_editable_insert_text (GTK_EDITABLE(entry), text, strlen (text), &tmp_pos);
+  GTK_EDITABLE(entry)->current_pos = tmp_pos;
+}
+
+void
+gtk_entry_prepend_text (GtkEntry *entry,
+			const gchar *text)
+{
+  gint tmp_pos;
+
+  g_return_if_fail (entry != NULL);
+  g_return_if_fail (GTK_IS_ENTRY (entry));
+  g_return_if_fail (text != NULL);
+
+  tmp_pos = 0;
+  gtk_editable_insert_text (GTK_EDITABLE(entry), text, strlen (text), &tmp_pos);
+  GTK_EDITABLE(entry)->current_pos = tmp_pos;
+}
+
+void
+gtk_entry_set_position (GtkEntry *entry,
+			gint      position)
+{
+  g_return_if_fail (entry != NULL);
+  g_return_if_fail (GTK_IS_ENTRY (entry));
+
+  if ((position == -1) || (position > entry->text_length))
+    GTK_EDITABLE(entry)->current_pos = entry->text_length;
+  else
+    GTK_EDITABLE(entry)->current_pos = position;
+  entry_adjust_scroll (entry);
+}
+
+static void
+gtk_entry_set_position_from_editable (GtkEditable *editable,
+				      gint position)
+{
+  gtk_entry_set_position (GTK_ENTRY (editable), position);
+}
+
+void
+gtk_entry_set_visibility (GtkEntry *entry,
+			  gboolean visible)
+{
+  g_return_if_fail (entry != NULL);
+  g_return_if_fail (GTK_IS_ENTRY (entry));
+
+  entry->visible = visible ? TRUE : FALSE;
+  GTK_EDITABLE (entry)->visible = visible ? TRUE : FALSE;
+  gtk_entry_recompute_offsets (entry);
+  gtk_widget_queue_draw (GTK_WIDGET (entry));
+}
+
+void
+gtk_entry_set_editable(GtkEntry *entry,
+		       gboolean  editable)
+{
+  g_return_if_fail (entry != NULL);
+  g_return_if_fail (GTK_IS_ENTRY (entry));
+
+  gtk_editable_set_editable (GTK_EDITABLE (entry), editable);
+}
+
+gchar*
+gtk_entry_get_text (GtkEntry *entry)
+{
+  g_return_val_if_fail (entry != NULL, NULL);
+  g_return_val_if_fail (GTK_IS_ENTRY (entry), NULL);
+
+  if (!entry->text_mb_dirty)
+    return entry->text_mb;
+
+  if (entry->text_mb)
+    g_free(entry->text_mb);
+
+  if (!entry->text)
+    {
+      entry->text_mb = g_new(gchar, 1);
+      entry->text_mb[0] = 0;
+    }
+  else
+    {
+      entry->text_mb = gtk_entry_get_chars(GTK_EDITABLE(entry), 0, -1);
+    }
+  entry->text_mb_dirty = 0;
+
+  return entry->text_mb;
+}
+
+static void
+gtk_entry_finalize (GtkObject *object)
+{
+  GtkEntry *entry;
+
+  g_return_if_fail (object != NULL);
+  g_return_if_fail (GTK_IS_ENTRY (object));
+
+  entry = GTK_ENTRY (object);
+
+  if (entry->timer)
+    gtk_timeout_remove (entry->timer);
+
+  entry->text_size = 0;
+
+  if (entry->text)
+    g_free (entry->text);
+  if (entry->char_offset)
+    g_free (entry->char_offset);
+  entry->text = NULL;
+
+  if (entry->text_mb)
+    g_free (entry->text_mb);
+  entry->text_mb = NULL;
+ 
+  if (entry->backing_pixmap)
+    gdk_pixmap_unref (entry->backing_pixmap);
+
+  (* GTK_OBJECT_CLASS (parent_class)->finalize) (object);
+}
+
+static void
+gtk_entry_realize (GtkWidget *widget)
+{
+  GtkEntry *entry;
+  GtkEditable *editable;
+  GtkRequisition requisition;
+  GdkWindowAttr attributes;
+  gint attributes_mask;
+
+  g_return_if_fail (widget != NULL);
+  g_return_if_fail (GTK_IS_ENTRY (widget));
+
+  GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
+  entry = GTK_ENTRY (widget);
+  editable = GTK_EDITABLE (widget);
+
+  gtk_widget_get_child_requisition (widget, &requisition);
+  
+  attributes.window_type = GDK_WINDOW_CHILD;
+  attributes.x = widget->allocation.x;
+  attributes.y = widget->allocation.y + (widget->allocation.height -
+					 requisition.height) / 2;
+  attributes.width = widget->allocation.width;
+  attributes.height = requisition.height;
+  attributes.wclass = GDK_INPUT_OUTPUT;
+  attributes.visual = gtk_widget_get_visual (widget);
+  attributes.colormap = gtk_widget_get_colormap (widget);
+  attributes.event_mask = gtk_widget_get_events (widget);
+  attributes.event_mask |= (GDK_EXPOSURE_MASK |
+			    GDK_BUTTON_PRESS_MASK |
+			    GDK_BUTTON_RELEASE_MASK |
+			    GDK_BUTTON1_MOTION_MASK |
+			    GDK_BUTTON3_MOTION_MASK |
+			    GDK_POINTER_MOTION_HINT_MASK |
+			    GDK_ENTER_NOTIFY_MASK |
+			    GDK_LEAVE_NOTIFY_MASK |
+			    GDK_KEY_PRESS_MASK);
+  attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
+
+  widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
+  gdk_window_set_user_data (widget->window, entry);
+
+  attributes.x = widget->style->klass->xthickness;
+  attributes.y = widget->style->klass->ythickness;
+  attributes.width = widget->allocation.width - attributes.x * 2;
+  attributes.height = requisition.height - attributes.y * 2;
+  attributes.cursor = entry->cursor = gdk_cursor_new (GDK_XTERM);
+  attributes_mask |= GDK_WA_CURSOR;
+
+  entry->text_area = gdk_window_new (widget->window, &attributes, attributes_mask);
+  gdk_window_set_user_data (entry->text_area, entry);
+
+  widget->style = gtk_style_attach (widget->style, widget->window);
+
+  gdk_window_set_background (widget->window, &widget->style->base[GTK_WIDGET_STATE (widget)]);
+  gdk_window_set_background (entry->text_area, &widget->style->base[GTK_WIDGET_STATE (widget)]);
+
+#ifdef USE_XIM
+  if (gdk_im_ready () && (editable->ic_attr = gdk_ic_attr_new ()) != NULL)
+    {
+      gint width, height;
+      GdkEventMask mask;
+      GdkColormap *colormap;
+      GdkICAttr *attr = editable->ic_attr;
+      GdkICAttributesType attrmask = GDK_IC_ALL_REQ;
+      GdkIMStyle style;
+      GdkIMStyle supported_style = GDK_IM_PREEDIT_NONE |
+				   GDK_IM_PREEDIT_NOTHING |
+			           GDK_IM_PREEDIT_POSITION |
+			           GDK_IM_STATUS_NONE |
+				   GDK_IM_STATUS_NOTHING;
+
+      if (widget->style && widget->style->font->type != GDK_FONT_FONTSET)
+	supported_style &= ~GDK_IM_PREEDIT_POSITION;
+
+      attr->style = style = gdk_im_decide_style (supported_style);
+      attr->client_window = entry->text_area;
+
+      if ((colormap = gtk_widget_get_colormap (widget)) !=
+	    gtk_widget_get_default_colormap ())
+	{
+	  attrmask |= GDK_IC_PREEDIT_COLORMAP;
+	  attr->preedit_colormap = colormap;
+	}
+      attrmask |= GDK_IC_PREEDIT_FOREGROUND;
+      attrmask |= GDK_IC_PREEDIT_BACKGROUND;
+      attr->preedit_foreground = widget->style->fg[GTK_STATE_NORMAL];
+      attr->preedit_background = widget->style->base[GTK_STATE_NORMAL];
+
+      switch (style & GDK_IM_PREEDIT_MASK)
+	{
+	case GDK_IM_PREEDIT_POSITION:
+	  if (widget->style && widget->style->font->type != GDK_FONT_FONTSET)
+	    {
+	      g_warning ("over-the-spot style requires fontset");
+	      break;
+	    }
+
+	  gdk_window_get_size (entry->text_area, &width, &height);
+
+	  attrmask |= GDK_IC_PREEDIT_POSITION_REQ;
+	  attr->spot_location.x = 0;
+	  attr->spot_location.y = height;
+	  attr->preedit_area.x = 0;
+	  attr->preedit_area.y = 0;
+	  attr->preedit_area.width = width;
+	  attr->preedit_area.height = height;
+	  attr->preedit_fontset = widget->style->font;
+
+	  break;
+	}
+      editable->ic = gdk_ic_new (attr, attrmask);
+     
+      if (editable->ic == NULL)
+	g_warning ("Can't create input context.");
+      else
+	{
+	  mask = gdk_window_get_events (entry->text_area);
+	  mask |= gdk_ic_get_events (editable->ic);
+	  gdk_window_set_events (entry->text_area, mask);
+
+	  if (GTK_WIDGET_HAS_FOCUS(widget))
+	    gdk_im_begin (editable->ic, entry->text_area);
+	}
+    }
+#endif
+
+  gdk_window_show (entry->text_area);
+
+  if (editable->selection_start_pos != editable->selection_end_pos)
+    gtk_editable_claim_selection (editable, TRUE, GDK_CURRENT_TIME);
+
+  gtk_entry_recompute_offsets (entry);
+}
+
+static void
+gtk_entry_unrealize (GtkWidget *widget)
+{
+  GtkEntry *entry;
+
+  g_return_if_fail (widget != NULL);
+  g_return_if_fail (GTK_IS_ENTRY (widget));
+
+  entry = GTK_ENTRY (widget);
+
+#ifdef USE_XIM
+  if (GTK_EDITABLE (widget)->ic)
+    {
+      gdk_ic_destroy (GTK_EDITABLE (widget)->ic);
+      GTK_EDITABLE (widget)->ic = NULL;
+    }
+  if (GTK_EDITABLE (widget)->ic_attr)
+    {
+      gdk_ic_attr_destroy (GTK_EDITABLE (widget)->ic_attr);
+      GTK_EDITABLE (widget)->ic_attr = NULL;
+    }
+#endif
+
+  if (entry->text_area)
+    {
+      gdk_window_set_user_data (entry->text_area, NULL);
+      gdk_window_destroy (entry->text_area);
+      entry->text_area = NULL;
+      gdk_cursor_destroy (entry->cursor);
+      entry->cursor = NULL;
+    }
+
+  if (GTK_WIDGET_CLASS (parent_class)->unrealize)
+    (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
+}
+
+static void
+gtk_entry_draw_focus (GtkWidget *widget)
+{
+  gint width, height;
+  gint x, y;
+
+  g_return_if_fail (widget != NULL);
+  g_return_if_fail (GTK_IS_ENTRY (widget));
+
+  if (GTK_WIDGET_DRAWABLE (widget))
+    {
+      x = 0;
+      y = 0;
+      gdk_window_get_size (widget->window, &width, &height);
+
+      if (GTK_WIDGET_HAS_FOCUS (widget))
+	{
+	  x += 1;
+	  y += 1;
+	  width -= 2;
+	  height -= 2;
+	}
+
+      gtk_paint_shadow (widget->style, widget->window,
+			GTK_STATE_NORMAL, GTK_SHADOW_IN,
+			NULL, widget, "entry",
+			x, y, width, height);
+
+      if (GTK_WIDGET_HAS_FOCUS (widget))
+	{
+	   gdk_window_get_size (widget->window, &width, &height);
+	   gtk_paint_focus (widget->style, widget->window, 
+			    NULL, widget, "entry",
+			    0, 0, width - 1, height - 1);
+	}
+
+      if (GTK_EDITABLE (widget)->editable)
+	gtk_entry_draw_cursor (GTK_ENTRY (widget));
+    }
+}
+
+static void
+gtk_entry_size_request (GtkWidget      *widget,
+			GtkRequisition *requisition)
+{
+  g_return_if_fail (widget != NULL);
+  g_return_if_fail (GTK_IS_ENTRY (widget));
+  g_return_if_fail (requisition != NULL);
+
+  requisition->width = MIN_ENTRY_WIDTH + (widget->style->klass->xthickness + INNER_BORDER) * 2;
+  requisition->height = (widget->style->font->ascent +
+			 widget->style->font->descent +
+			 (widget->style->klass->ythickness + INNER_BORDER) * 2);
+}
+
+static void
+gtk_entry_size_allocate (GtkWidget     *widget,
+			 GtkAllocation *allocation)
+{
+  GtkEntry *entry;
+  GtkEditable *editable;
+
+  g_return_if_fail (widget != NULL);
+  g_return_if_fail (GTK_IS_ENTRY (widget));
+  g_return_if_fail (allocation != NULL);
+
+  widget->allocation = *allocation;
+  entry = GTK_ENTRY (widget);
+  editable = GTK_EDITABLE (widget);
+
+  if (GTK_WIDGET_REALIZED (widget))
+    {
+      /* We call gtk_widget_get_child_requisition, since we want (for
+       * backwards compatibility reasons) the realization here to
+       * be affected by the usize of the entry, if set
+       */
+      GtkRequisition requisition;
+      gtk_widget_get_child_requisition (widget, &requisition);
+  
+      gdk_window_move_resize (widget->window,
+			      allocation->x,
+			      allocation->y + (allocation->height - requisition.height) / 2,
+			      allocation->width, requisition.height);
+      gdk_window_move_resize (entry->text_area,
+			      widget->style->klass->xthickness,
+			      widget->style->klass->ythickness,
+			      allocation->width - widget->style->klass->xthickness * 2,
+			      requisition.height - widget->style->klass->ythickness * 2);
+
+      /* And make sure the cursor is on screen */
+      entry_adjust_scroll (entry);
+      
+#ifdef USE_XIM
+      if (editable->ic &&
+	  (gdk_ic_get_style (editable->ic) & GDK_IM_PREEDIT_POSITION))
+	{
+	  gint width, height;
+
+	  gdk_window_get_size (entry->text_area, &width, &height);
+	  editable->ic_attr->preedit_area.width = width;
+	  editable->ic_attr->preedit_area.height = height;
+	  gdk_ic_set_attr (editable->ic, editable->ic_attr,
+	      		   GDK_IC_PREEDIT_AREA);
+	}
+#endif
+    }
+}
+
+static void
+gtk_entry_draw (GtkWidget    *widget,
+		GdkRectangle *area)
+{
+  g_return_if_fail (widget != NULL);
+  g_return_if_fail (GTK_IS_ENTRY (widget));
+  g_return_if_fail (area != NULL);
+
+  if (GTK_WIDGET_DRAWABLE (widget))
+    {
+      gtk_widget_draw_focus (widget);
+      gtk_entry_draw_text (GTK_ENTRY (widget));
+    }
+}
+
+static gint
+gtk_entry_expose (GtkWidget      *widget,
+		  GdkEventExpose *event)
+{
+  GtkEntry *entry;
+
+  g_return_val_if_fail (widget != NULL, FALSE);
+  g_return_val_if_fail (GTK_IS_ENTRY (widget), FALSE);
+  g_return_val_if_fail (event != NULL, FALSE);
+
+  entry = GTK_ENTRY (widget);
+
+  if (widget->window == event->window)
+    gtk_widget_draw_focus (widget);
+  else if (entry->text_area == event->window)
+    gtk_entry_draw_text (GTK_ENTRY (widget));
+
+  return FALSE;
+}
+
+static gint
+gtk_entry_button_press (GtkWidget      *widget,
+			GdkEventButton *event)
+{
+  GtkEntry *entry;
+  GtkEditable *editable;
+  gint tmp_pos;
+
+  g_return_val_if_fail (widget != NULL, FALSE);
+  g_return_val_if_fail (GTK_IS_ENTRY (widget), FALSE);
+  g_return_val_if_fail (event != NULL, FALSE);
+
+  if (ctext_atom == GDK_NONE)
+    ctext_atom = gdk_atom_intern ("COMPOUND_TEXT", FALSE);
+
+  entry = GTK_ENTRY (widget);
+  editable = GTK_EDITABLE (widget);
+  
+  if (entry->button && (event->button != entry->button))
+    return FALSE;
+
+  entry->button = event->button;
+  
+  if (!GTK_WIDGET_HAS_FOCUS (widget))
+    gtk_widget_grab_focus (widget);
+
+  if (event->button == 1)
+    {
+      switch (event->type)
+	{
+	case GDK_BUTTON_PRESS:
+	  gtk_grab_add (widget);
+
+	  tmp_pos = gtk_entry_position (entry, event->x + entry->scroll_offset);
+	  /* Set it now, so we display things right. We'll unset it
+	   * later if things don't work out */
+	  editable->has_selection = TRUE;
+	  gtk_entry_set_selection (editable, tmp_pos, tmp_pos);
+	  editable->current_pos = editable->selection_start_pos;
+	  break;
+
+	case GDK_2BUTTON_PRESS:
+	  gtk_select_word (entry, event->time);
+	  break;
+
+	case GDK_3BUTTON_PRESS:
+	  gtk_select_line (entry, event->time);
+	  break;
+
+	default:
+	  break;
+	}
+
+      return TRUE;
+    }
+  else if (event->type == GDK_BUTTON_PRESS)
+    {
+      if ((event->button == 2) && editable->editable)
+	{
+	  if (editable->selection_start_pos == editable->selection_end_pos ||
+	      editable->has_selection)
+	    editable->current_pos = gtk_entry_position (entry, event->x + entry->scroll_offset);
+	  gtk_selection_convert (widget, GDK_SELECTION_PRIMARY,
+				 ctext_atom, event->time);
+	}
+      else
+	{
+	  gtk_grab_add (widget);
+
+	  tmp_pos = gtk_entry_position (entry, event->x + entry->scroll_offset);
+	  gtk_entry_set_selection (editable, tmp_pos, tmp_pos);
+	  editable->has_selection = FALSE;
+	  editable->current_pos = editable->selection_start_pos;
+
+	  if (gdk_selection_owner_get (GDK_SELECTION_PRIMARY) == widget->window)
+	    gtk_selection_owner_set (NULL, GDK_SELECTION_PRIMARY, event->time);
+	}
+
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+static gint
+gtk_entry_button_release (GtkWidget      *widget,
+			  GdkEventButton *event)
+{
+  GtkEntry *entry;
+  GtkEditable *editable;
+
+  g_return_val_if_fail (widget != NULL, FALSE);
+  g_return_val_if_fail (GTK_IS_ENTRY (widget), FALSE);
+  g_return_val_if_fail (event != NULL, FALSE);
+
+  entry = GTK_ENTRY (widget);
+  editable = GTK_EDITABLE (widget);
+
+  if (entry->button != event->button)
+    return FALSE;
+
+  entry->button = 0;
+  
+  if (event->button == 1)
+    {
+      gtk_grab_remove (widget);
+
+      editable->has_selection = FALSE;
+      if (editable->selection_start_pos != editable->selection_end_pos)
+	{
+	  if (gtk_selection_owner_set (widget,
+				       GDK_SELECTION_PRIMARY,
+				       event->time))
+	    editable->has_selection = TRUE;
+	  else
+	    gtk_entry_queue_draw (entry);
+	}
+      else
+	{
+	  if (gdk_selection_owner_get (GDK_SELECTION_PRIMARY) == widget->window)
+	    gtk_selection_owner_set (NULL, GDK_SELECTION_PRIMARY, event->time);
+	}
+
+      return TRUE;
+    }
+  else if (event->button == 3)
+    {
+      gtk_grab_remove (widget);
+
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+static gint
+gtk_entry_motion_notify (GtkWidget      *widget,
+			 GdkEventMotion *event)
+{
+  GtkEntry *entry;
+  gint x;
+
+  g_return_val_if_fail (widget != NULL, FALSE);
+  g_return_val_if_fail (GTK_IS_ENTRY (widget), FALSE);
+  g_return_val_if_fail (event != NULL, FALSE);
+
+  entry = GTK_ENTRY (widget);
+
+  if (entry->button == 0)
+    return FALSE;
+
+  x = event->x;
+  if (event->is_hint || (entry->text_area != event->window))
+    gdk_window_get_pointer (entry->text_area, &x, NULL, NULL);
+
+  GTK_EDITABLE(entry)->selection_end_pos = gtk_entry_position (entry, x + entry->scroll_offset);
+  GTK_EDITABLE(entry)->current_pos = GTK_EDITABLE(entry)->selection_end_pos;
+  entry_adjust_scroll (entry);
+  gtk_entry_queue_draw (entry);
+
+  return TRUE;
+}
+
+static gint
+gtk_entry_key_press (GtkWidget   *widget,
+		     GdkEventKey *event)
+{
+  GtkEntry *entry;
+  GtkEditable *editable;
+
+  gint return_val;
+  gint key;
+  guint initial_pos;
+  gint extend_selection;
+  gint extend_start;
+
+  g_return_val_if_fail (widget != NULL, FALSE);
+  g_return_val_if_fail (GTK_IS_ENTRY (widget), FALSE);
+  g_return_val_if_fail (event != NULL, FALSE);
+
+  entry = GTK_ENTRY (widget);
+  editable = GTK_EDITABLE (widget);
+  return_val = FALSE;
+
+  if(editable->editable == FALSE)
+    return FALSE;
+
+  initial_pos = editable->current_pos;
+
+  extend_selection = event->state & GDK_SHIFT_MASK;
+  extend_start = FALSE;
+
+  if (extend_selection)
+    {
+      if (editable->selection_start_pos == editable->selection_end_pos)
+	{
+	  editable->selection_start_pos = editable->current_pos;
+	  editable->selection_end_pos = editable->current_pos;
+	}
+      
+      extend_start = (editable->current_pos == editable->selection_start_pos);
+    }
+
+  switch (event->keyval)
+    {
+    case GDK_BackSpace:
+      return_val = TRUE;
+      if (event->state & GDK_CONTROL_MASK)
+	gtk_delete_backward_word (entry);
+      else
+	gtk_delete_backward_character (entry);
+      break;
+    case GDK_Clear:
+      return_val = TRUE;
+      gtk_delete_line (entry);
+      break;
+    case GDK_Insert:
+      return_val = TRUE;
+      if (event->state & GDK_SHIFT_MASK)
+	{
+	  extend_selection = FALSE;
+	  gtk_editable_paste_clipboard (editable);
+	}
+      else if (event->state & GDK_CONTROL_MASK)
+	{
+	  gtk_editable_copy_clipboard (editable);
+	}
+      else
+	{
+	  /* gtk_toggle_insert(entry) -- IMPLEMENT */
+	}
+      break;
+    case GDK_Delete:
+      return_val = TRUE;
+      if (event->state & GDK_CONTROL_MASK)
+	gtk_delete_forward_word (entry);
+      else if (event->state & GDK_SHIFT_MASK)
+	{
+	  extend_selection = FALSE;
+	  gtk_editable_cut_clipboard (editable);
+	}
+      else
+	gtk_delete_forward_character (entry);
+      break;
+    case GDK_Home:
+      return_val = TRUE;
+      gtk_move_beginning_of_line (entry);
+      break;
+    case GDK_End:
+      return_val = TRUE;
+      gtk_move_end_of_line (entry);
+      break;
+    case GDK_Left:
+      return_val = TRUE;
+      if (!extend_selection &&
+	  editable->selection_start_pos != editable->selection_end_pos)
+	{
+	  editable->current_pos = MIN (editable->selection_start_pos, editable->selection_end_pos);
+	  initial_pos = (guint)-1; /* Force redraw below */
+	}
+      else
+	{
+	  if (event->state & GDK_CONTROL_MASK)
+	    gtk_move_backward_word (entry);
+	  else
+	    gtk_move_backward_character (entry);
+	}
+      break;
+    case GDK_Right:
+      return_val = TRUE;
+      if (!extend_selection &&
+	  editable->selection_start_pos != editable->selection_end_pos)
+	{
+	  editable->current_pos = MAX (editable->selection_start_pos, editable->selection_end_pos);
+	  initial_pos = (guint)-1; /* Force redraw below */
+	}
+      else
+	{
+	  if (event->state & GDK_CONTROL_MASK)
+	    gtk_move_forward_word (entry);
+	  else
+	    gtk_move_forward_character (entry);
+	}
+      break;
+    case GDK_Return:
+      return_val = TRUE;
+      gtk_widget_activate (widget);
+      break;
+    /* The next two keys should not be inserted literally. Any others ??? */
+    case GDK_Tab:
+    case GDK_Escape:
+      break;
+    default:
+      if ((event->keyval >= 0x20) && (event->keyval <= 0xFF))
+	{
+	  key = event->keyval;
+
+	  if (event->state & GDK_CONTROL_MASK)
+	    {
+	      if ((key >= 'A') && (key <= 'Z'))
+		key -= 'A' - 'a';
+
+	      if ((key >= 'a') && (key <= 'z') && control_keys[key - 'a'])
+		{
+		  (* control_keys[key - 'a']) (editable, event->time);
+		  return_val = TRUE;
+		}
+	      break;
+	    }
+	  else if (event->state & GDK_MOD1_MASK)
+	    {
+	      if ((key >= 'A') && (key <= 'Z'))
+		key -= 'A' - 'a';
+
+	      if ((key >= 'a') && (key <= 'z') && alt_keys[key - 'a'])
+		{
+		  (* alt_keys[key - 'a']) (editable, event->time);
+		  return_val = TRUE;
+		}
+	      break;
+	    }
+	}
+      if (event->length > 0)
+	{
+	  gint tmp_pos;
+
+	  extend_selection = FALSE;
+	  gtk_editable_delete_selection (editable);
+
+	  tmp_pos = editable->current_pos;
+	  gtk_editable_insert_text (editable, event->string, event->length, &tmp_pos);
+	  editable->current_pos = tmp_pos;
+
+	  return_val = TRUE;
+	}
+      break;
+    }
+
+  /* since we emit signals from within the above code,
+   * the widget might already be destroyed or at least
+   * unrealized.
+   */
+  if (GTK_WIDGET_REALIZED (editable) &&
+      return_val && (editable->current_pos != initial_pos))
+    {
+      if (extend_selection)
+	{
+	  if (editable->current_pos < editable->selection_start_pos)
+	    editable->selection_start_pos = editable->current_pos;
+	  else if (editable->current_pos > editable->selection_end_pos)
+	    editable->selection_end_pos = editable->current_pos;
+	  else
+	    {
+	      if (extend_start)
+		editable->selection_start_pos = editable->current_pos;
+	      else
+		editable->selection_end_pos = editable->current_pos;
+	    }
+	}
+      else
+	{
+	  editable->selection_start_pos = 0;
+	  editable->selection_end_pos = 0;
+	}
+
+      gtk_editable_claim_selection (editable,
+				    editable->selection_start_pos != editable->selection_end_pos,
+				    event->time);
+      
+      entry_adjust_scroll (entry);
+      gtk_entry_queue_draw (entry);
+    }
+
+  return return_val;
+}
+
+static gint
+gtk_entry_focus_in (GtkWidget     *widget,
+		    GdkEventFocus *event)
+{
+  g_return_val_if_fail (widget != NULL, FALSE);
+  g_return_val_if_fail (GTK_IS_ENTRY (widget), FALSE);
+  g_return_val_if_fail (event != NULL, FALSE);
+
+  GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
+  gtk_widget_draw_focus (widget);
+
+#ifdef USE_XIM
+  if (GTK_EDITABLE(widget)->ic)
+    gdk_im_begin (GTK_EDITABLE(widget)->ic, GTK_ENTRY(widget)->text_area);
+#endif
+
+  return FALSE;
+}
+
+static gint
+gtk_entry_focus_out (GtkWidget     *widget,
+		     GdkEventFocus *event)
+{
+  g_return_val_if_fail (widget != NULL, FALSE);
+  g_return_val_if_fail (GTK_IS_ENTRY (widget), FALSE);
+  g_return_val_if_fail (event != NULL, FALSE);
+
+  GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
+  gtk_widget_draw_focus (widget);
+
+#ifdef USE_XIM
+  gdk_im_end ();
+#endif
+
+  return FALSE;
+}
+
+static void
+gtk_entry_make_backing_pixmap (GtkEntry *entry, gint width, gint height)
+{
+  gint pixmap_width, pixmap_height;
+
+  if (!entry->backing_pixmap)
+    {
+      /* allocate */
+      entry->backing_pixmap = gdk_pixmap_new (entry->text_area,
+					      width, height,
+					      -1);
+    }
+  else
+    {
+      /* reallocate if sizes don't match */
+      gdk_window_get_size (entry->backing_pixmap,
+			   &pixmap_width, &pixmap_height);
+      if ((pixmap_width != width) || (pixmap_height != height))
+	{
+	  gdk_pixmap_unref (entry->backing_pixmap);
+	  entry->backing_pixmap = gdk_pixmap_new (entry->text_area,
+						  width, height,
+						  -1);
+	}
+    }
+}
+
+static void
+gtk_entry_draw_text (GtkEntry *entry)
+{
+  GtkWidget *widget;
+  GtkEditable *editable;
+  GtkStateType selected_state;
+  gint start_pos;
+  gint end_pos;
+  gint start_xoffset;
+  gint selection_start_pos;
+  gint selection_end_pos;
+  gint selection_start_xoffset;
+  gint selection_end_xoffset;
+  gint width, height;
+  gint y;
+  GdkDrawable *drawable;
+  gint use_backing_pixmap;
+  GdkWChar *stars;
+  GdkWChar *toprint;
+
+  g_return_if_fail (entry != NULL);
+  g_return_if_fail (GTK_IS_ENTRY (entry));
+
+  if (entry->timer)
+    {
+      gtk_timeout_remove (entry->timer);
+      entry->timer = 0;
+    }
+
+  if (GTK_WIDGET_DRAWABLE (entry))
+    {
+      widget = GTK_WIDGET (entry);
+      editable = GTK_EDITABLE (entry);
+
+      if (!entry->text)
+	{	  
+	  gtk_paint_flat_box (widget->style, entry->text_area,
+			      GTK_WIDGET_STATE(widget), GTK_SHADOW_NONE,
+			      NULL, widget, "entry_bg", 
+			      0, 0, -1, -1);
+
+	  if (editable->editable)
+	    gtk_entry_draw_cursor (entry);
+	  return;
+	}
+
+      gdk_window_get_size (entry->text_area, &width, &height);
+
+      /*
+	If the widget has focus, draw on a backing pixmap to avoid flickering
+	and copy it to the text_area.
+	Otherwise draw to text_area directly for better speed.
+      */
+      use_backing_pixmap = GTK_WIDGET_HAS_FOCUS (widget) && (entry->text != NULL);
+      if (use_backing_pixmap)
+	{
+	   gtk_entry_make_backing_pixmap (entry, width, height);
+	   drawable = entry->backing_pixmap;
+	}
+       else
+	 {
+	    drawable = entry->text_area;
+	 }
+       gtk_paint_flat_box (widget->style, drawable, 
+			   GTK_WIDGET_STATE(widget), GTK_SHADOW_NONE,
+			   NULL, widget, "entry_bg", 
+			   0, 0, width, height);
+
+      y = (height - (widget->style->font->ascent + widget->style->font->descent)) / 2;
+      y += widget->style->font->ascent;
+
+      start_pos = gtk_entry_find_position (entry, entry->scroll_offset);
+      start_xoffset = entry->char_offset[start_pos] - entry->scroll_offset;
+
+      end_pos = gtk_entry_find_position (entry, entry->scroll_offset + width);
+      if (end_pos < entry->text_length)
+	end_pos += 1;
+
+      selected_state = GTK_STATE_SELECTED;
+      if (!editable->has_selection)
+	selected_state = GTK_STATE_ACTIVE;
+
+      selection_start_pos = MIN (editable->selection_start_pos, editable->selection_end_pos);
+      selection_end_pos = MAX (editable->selection_start_pos, editable->selection_end_pos);
+      
+      selection_start_pos = CLAMP (selection_start_pos, start_pos, end_pos);
+      selection_end_pos = CLAMP (selection_end_pos, start_pos, end_pos);
+
+      selection_start_xoffset = 
+	entry->char_offset[selection_start_pos] - entry->scroll_offset;
+      selection_end_xoffset = 
+	entry->char_offset[selection_end_pos] -entry->scroll_offset;
+
+      /* if editable->visible, print a bunch of stars.  If not, print the standard text. */
+      if (editable->visible)
+	{
+	  toprint = entry->text + start_pos;
+	}
+      else
+	{
+	  gint i;
+	  GdkWChar invisible_char = gtk_entry_get_invisible_char (entry);
+	  
+	  stars = g_new (GdkWChar, end_pos - start_pos);
+	  for (i = 0; i < end_pos - start_pos; i++)
+	    stars[i] = invisible_char;
+	  toprint = stars;
+	}
+      
+      if (selection_start_pos > start_pos)
+	gtk_entry_draw_wchars (entry, drawable, widget->style->font,
+			       widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
+			       INNER_BORDER + start_xoffset, y,
+			       toprint,
+			       selection_start_pos - start_pos);
+      
+      if ((selection_end_pos >= start_pos) && 
+	  (selection_start_pos < end_pos) &&
+	  (selection_start_pos != selection_end_pos))
+	 {
+	    gtk_paint_flat_box (widget->style, drawable, 
+				selected_state, GTK_SHADOW_NONE,
+				NULL, widget, "text",
+				INNER_BORDER + selection_start_xoffset,
+				INNER_BORDER,
+				selection_end_xoffset - selection_start_xoffset,
+				height - 2*INNER_BORDER);
+	    gtk_entry_draw_wchars (entry, drawable, widget->style->font,
+				   widget->style->fg_gc[selected_state],
+				   INNER_BORDER + selection_start_xoffset, y,
+				   toprint + selection_start_pos - start_pos,
+				   selection_end_pos - selection_start_pos);
+	 }	    
+       
+       if (selection_end_pos < end_pos)
+	 gtk_entry_draw_wchars (entry, drawable, widget->style->font,
+				widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
+				INNER_BORDER + selection_end_xoffset, y,
+				toprint + selection_end_pos - start_pos,
+				end_pos - selection_end_pos);
+       /* free the space allocated for the stars if it's neccessary. */
+      if (!editable->visible)
+	g_free (toprint);
+
+      if (editable->editable)
+	gtk_entry_draw_cursor_on_drawable (entry, drawable);
+
+      if (use_backing_pixmap)
+	gdk_draw_pixmap(entry->text_area,
+			widget->style->fg_gc[GTK_STATE_NORMAL],
+			entry->backing_pixmap,
+			0, 0, 0, 0, width, height);	  
+    }
+}
+
+static void
+gtk_entry_draw_cursor (GtkEntry *entry)
+{
+  g_return_if_fail (entry != NULL);
+  g_return_if_fail (GTK_IS_ENTRY (entry));
+
+  gtk_entry_draw_cursor_on_drawable (entry, entry->text_area);
+}
+
+static void
+gtk_entry_draw_cursor_on_drawable (GtkEntry *entry, GdkDrawable *drawable)
+{
+  GtkWidget *widget;
+  GtkEditable *editable;
+  gint xoffset;
+  gint text_area_height;
+
+  g_return_if_fail (entry != NULL);
+  g_return_if_fail (GTK_IS_ENTRY (entry));
+
+  if (GTK_WIDGET_DRAWABLE (entry))
+    {
+      widget = GTK_WIDGET (entry);
+      editable = GTK_EDITABLE (entry);
+
+      xoffset = INNER_BORDER + entry->char_offset[editable->current_pos];
+      xoffset -= entry->scroll_offset;
+
+      gdk_window_get_size (entry->text_area, NULL, &text_area_height);
+
+      if (GTK_WIDGET_HAS_FOCUS (widget) &&
+	  (editable->selection_start_pos == editable->selection_end_pos))
+	{
+	  gdk_draw_line (drawable, widget->style->fg_gc[GTK_STATE_NORMAL], 
+			 xoffset, INNER_BORDER,
+			 xoffset, text_area_height - INNER_BORDER);
+	}
+      else
+	{
+	  gint yoffset = 
+	    (text_area_height - 
+	     (widget->style->font->ascent + widget->style->font->descent)) / 2
+	    + widget->style->font->ascent;
+
+	  gtk_paint_flat_box (widget->style, drawable,
+			      GTK_WIDGET_STATE(widget), GTK_SHADOW_NONE,
+			      NULL, widget, "entry_bg", 
+			      xoffset, INNER_BORDER, 
+			      1, text_area_height - INNER_BORDER);
+	  
+	  /* Draw the character under the cursor again
+	   */
+	  if ((editable->current_pos < entry->text_length) &&
+	      (editable->selection_start_pos == editable->selection_end_pos))
+	    {
+	      GdkWChar c = editable->visible ?
+		                 *(entry->text + editable->current_pos) :
+		                 '*';
+	      
+	      gtk_entry_draw_wchars (entry, drawable, widget->style->font,
+				     widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
+				     xoffset, yoffset, &c, 1);
+	    }
+	}
+
+
+#ifdef USE_XIM
+      if (GTK_WIDGET_HAS_FOCUS(widget) && gdk_im_ready() && editable->ic && 
+	  (gdk_ic_get_style (editable->ic) & GDK_IM_PREEDIT_POSITION))
+	{
+	  editable->ic_attr->spot_location.x = xoffset;
+	  editable->ic_attr->spot_location.y =
+	    (text_area_height + (widget->style->font->ascent
+	        - widget->style->font->descent) + 1) / 2;
+
+	  gdk_ic_set_attr (editable->ic,
+	      		   editable->ic_attr, GDK_IC_SPOT_LOCATION);
+	}
+#endif 
+    }
+}
+
+static void
+gtk_entry_queue_draw (GtkEntry *entry)
+{
+  g_return_if_fail (entry != NULL);
+  g_return_if_fail (GTK_IS_ENTRY (entry));
+
+  if (!entry->timer)
+    entry->timer = gtk_timeout_add (DRAW_TIMEOUT, gtk_entry_timer, entry);
+}
+
+static gint
+gtk_entry_timer (gpointer data)
+{
+  GtkEntry *entry;
+
+  GDK_THREADS_ENTER ();
+
+  entry = GTK_ENTRY (data);
+  entry->timer = 0;
+  gtk_entry_draw_text (entry);
+
+  GDK_THREADS_LEAVE ();
+
+  return FALSE;
+}
+
+static gint
+gtk_entry_find_position (GtkEntry *entry,
+			 gint      x)
+{
+  gint start = 0;
+  gint end = entry->text_length;
+  gint half;
+
+  if (x <= 0)
+    return 0;
+  if (x >= entry->char_offset[end])
+    return end;
+  
+  /* invariant - char_offset[start] <= x < char_offset[end] */
+
+  while (start != end)
+    {
+      half = (start+end)/2;
+      if (half == start)
+	return half;
+      else if (entry->char_offset[half] <= x)
+	start = half;
+      else
+	end = half;
+    }
+
+  return start;
+}
+
+static gint
+gtk_entry_position (GtkEntry *entry,
+		    gint      x)
+{
+  return gtk_entry_find_position(entry, x);
+}
+
+static void
+entry_adjust_scroll (GtkEntry *entry)
+{
+  gint xoffset, max_offset;
+  gint text_area_width;
+
+  g_return_if_fail (entry != NULL);
+  g_return_if_fail (GTK_IS_ENTRY (entry));
+
+  if (!entry->text_area)
+    return;
+
+  gdk_window_get_size (entry->text_area, &text_area_width, NULL);
+  text_area_width -= 2 * INNER_BORDER;
+
+  /* Display as much text as we can */
+  max_offset = MAX(0, entry->char_offset[entry->text_length] - text_area_width);
+
+  if (entry->scroll_offset > max_offset)
+    entry->scroll_offset = max_offset;
+
+  /* And make sure cursor is on screen. Note that the cursor is
+   * actually drawn one pixel into the INNER_BORDER space on
+   * the right, when the scroll is at the utmost right. This
+   * looks better to to me than confining the cursor inside the
+   * border entirely, though it means that the cursor gets one
+   * pixel closer to the the edge of the widget on the right than
+   * on the left. This might need changing if one changed
+   * INNER_BORDER from 2 to 1, as one would do on a
+   * small-screen-real-estate display.
+   */
+  xoffset = entry->char_offset[GTK_EDITABLE(entry)->current_pos];
+  xoffset -= entry->scroll_offset;
+
+  if (xoffset < 0)
+    entry->scroll_offset += xoffset;
+  else if (xoffset > text_area_width)
+    entry->scroll_offset += xoffset - text_area_width;
+
+  gtk_widget_queue_draw (GTK_WIDGET (entry));
+}
+
+static void
+gtk_entry_grow_text (GtkEntry *entry)
+{
+  gint previous_size;
+  gint i;
+
+  g_return_if_fail (entry != NULL);
+  g_return_if_fail (GTK_IS_ENTRY (entry));
+
+  previous_size = entry->text_size;
+  if (!entry->text_size)
+    entry->text_size = 128;
+  else
+    entry->text_size *= 2;
+  entry->text = g_realloc (entry->text, entry->text_size * sizeof(GdkWChar));
+  entry->char_offset = g_realloc (entry->char_offset, 
+				  entry->text_size * sizeof(guint));
+
+  if (entry->text_length == 0)	/* initial allocation */
+    {
+      entry->char_offset[0] = 0;
+    }
+
+  for (i = previous_size; i < entry->text_size; i++)
+    entry->text[i] = '\0';
+}
+
+static void
+gtk_entry_insert_text (GtkEditable *editable,
+		       const gchar *new_text,
+		       gint         new_text_length,
+		       gint        *position)
+{
+  GdkWChar *text;
+  gint start_pos;
+  gint end_pos;
+  gint last_pos;
+  gint max_length;
+  gint i;
+
+  guchar *new_text_nt;
+  gint insertion_length;
+  GdkWChar *insertion_text;
+  
+  GtkEntry *entry;
+  GtkWidget *widget;
+  
+  g_return_if_fail (editable != NULL);
+  g_return_if_fail (GTK_IS_ENTRY (editable));
+
+  entry = GTK_ENTRY (editable);
+  widget = GTK_WIDGET (editable);
+
+  if ((entry->text_length == 0) && (entry->use_wchar == FALSE))
+    {
+      if (!GTK_WIDGET_REALIZED (widget))
+	gtk_widget_ensure_style (widget);
+      if ((widget->style) && (widget->style->font->type == GDK_FONT_FONTSET))
+	entry->use_wchar = TRUE;
+    }
+
+  if (new_text_length < 0)
+    {
+      new_text_nt = (gchar *)new_text;
+      new_text_length = strlen (new_text);
+      if (new_text_length <= 0) return;
+    }
+  else if (new_text_length == 0)
+    {
+      return;
+    }
+  else
+    {
+      /* make a null-terminated copy of new_text */
+      new_text_nt = g_new (gchar, new_text_length + 1);
+      memcpy (new_text_nt, new_text, new_text_length);
+      new_text_nt[new_text_length] = 0;
+    }
+    
+  /* The algorithms here will work as long as, the text size (a
+   * multiple of 2), fits into a guint16 but we specify a shorter
+   * maximum length so that if the user pastes a very long text, there
+   * is not a long hang from the slow X_LOCALE functions.  */
+ 
+  if (entry->text_max_length == 0)
+    max_length = 2047;
+  else
+    max_length = MIN (2047, entry->text_max_length);
+
+  /* Convert to wide characters */
+  insertion_text = g_new (GdkWChar, new_text_length);
+  if (entry->use_wchar)
+    insertion_length = gdk_mbstowcs (insertion_text, new_text_nt,
+				     new_text_length);
+  else
+    for (insertion_length=0; new_text_nt[insertion_length]; insertion_length++)
+      insertion_text[insertion_length] = new_text_nt[insertion_length];
+  if (new_text_nt != (guchar *)new_text)
+    g_free (new_text_nt);
+
+  /* Make sure we do not exceed the maximum size of the entry. */
+  if (insertion_length + entry->text_length > max_length)
+    insertion_length = max_length - entry->text_length;
+
+  /* Don't insert anything, if there was nothing to insert. */
+  if (insertion_length <= 0)
+    {
+      g_free(insertion_text);
+      return;
+    }
+
+  /* Make sure we are inserting at integral character position */
+  start_pos = *position;
+  if (start_pos < 0)
+    start_pos = 0;
+  else if (start_pos > entry->text_length)
+    start_pos = entry->text_length;
+
+  end_pos = start_pos + insertion_length;
+  last_pos = insertion_length + entry->text_length;
+
+  if (editable->selection_start_pos >= *position)
+    editable->selection_start_pos += insertion_length;
+  if (editable->selection_end_pos >= *position)
+    editable->selection_end_pos += insertion_length;
+
+  while (last_pos >= entry->text_size)
+    gtk_entry_grow_text (entry);
+
+  text = entry->text;
+  for (i = last_pos - 1; i >= end_pos; i--)
+    text[i] = text[i- (end_pos - start_pos)];
+  for (i = start_pos; i < end_pos; i++)
+    text[i] = insertion_text[i - start_pos];
+  g_free (insertion_text);
+
+  /* Fix up the the character offsets */
+  
+  if (GTK_WIDGET_REALIZED (entry))
+    {
+      gint offset = 0;
+      
+      for (i = last_pos; i >= end_pos; i--)
+	entry->char_offset[i] = entry->char_offset[i - insertion_length];
+      
+      for (i=start_pos; i<end_pos; i++)
+	{
+	  GdkWChar ch;
+
+	  entry->char_offset[i] = entry->char_offset[start_pos] + offset;
+
+	  if (editable->visible)
+	    ch = entry->text[i];
+	  else 
+	    ch = gtk_entry_get_invisible_char (entry);
+
+	  if (entry->use_wchar)
+	    offset += gdk_char_width_wc (GTK_WIDGET (entry)->style->font, ch);
+	  else
+	    offset += gdk_char_width (GTK_WIDGET (entry)->style->font, ch);
+	}
+      for (i = end_pos; i <= last_pos; i++)
+	entry->char_offset[i] += offset;
+    }
+
+  entry->text_length += insertion_length;
+  *position = end_pos;
+
+  entry->text_mb_dirty = 1;
+  gtk_entry_queue_draw (entry);
+}
+
+/* Recompute the x offsets of all characters in the buffer */
+static void
+gtk_entry_recompute_offsets (GtkEntry *entry)
+{
+  gint i;
+  gint offset = 0;
+  GtkEditable *editable = GTK_EDITABLE (entry);
+
+  for (i=0; i<entry->text_length; i++)
+    {
+      GdkWChar ch;
+
+      entry->char_offset[i] = offset;
+
+      if (editable->visible)
+	ch = entry->text[i];
+      else
+	ch = gtk_entry_get_invisible_char (entry);
+
+      if (entry->use_wchar)
+	offset += gdk_char_width_wc (GTK_WIDGET (entry)->style->font, ch);
+      else
+	offset += gdk_char_width (GTK_WIDGET (entry)->style->font, ch);
+    }
+  
+  entry->char_offset[i] = offset;
+}
+
+static void
+gtk_entry_delete_text (GtkEditable *editable,
+		       gint         start_pos,
+		       gint         end_pos)
+{
+  GdkWChar *text;
+  gint deletion_length;
+  gint i;
+
+  GtkEntry *entry;
+  
+  g_return_if_fail (editable != NULL);
+  g_return_if_fail (GTK_IS_ENTRY (editable));
+
+  entry = GTK_ENTRY (editable);
+
+  if (end_pos < 0)
+    end_pos = entry->text_length;
+
+  if (editable->selection_start_pos > start_pos)
+    editable->selection_start_pos -= MIN(end_pos, editable->selection_start_pos) - start_pos;
+  if (editable->selection_end_pos > start_pos)
+    editable->selection_end_pos -= MIN(end_pos, editable->selection_end_pos) - start_pos;
+  
+  if ((start_pos < end_pos) &&
+      (start_pos >= 0) &&
+      (end_pos <= entry->text_length))
+    {
+      text = entry->text;
+      deletion_length = end_pos - start_pos;
+
+      /* Fix up the character offsets */
+      if (GTK_WIDGET_REALIZED (entry))
+	{
+	  gint deletion_width = 
+	    entry->char_offset[end_pos] - entry->char_offset[start_pos];
+
+	  for (i = 0 ; i <= entry->text_length - end_pos; i++)
+	    entry->char_offset[start_pos+i] = entry->char_offset[end_pos+i] - deletion_width;
+	}
+
+      for (i = end_pos; i < entry->text_length; i++)
+        text[i - deletion_length] = text[i];
+
+      for (i = entry->text_length - deletion_length; i < entry->text_length; i++)
+        text[i] = '\0';
+
+      entry->text_length -= deletion_length;
+      editable->current_pos = start_pos;
+    }
+
+  entry->text_mb_dirty = 1;
+  gtk_entry_queue_draw (entry);
+}
+
+static void
+gtk_entry_update_text (GtkEditable *editable,
+		       gint         start_pos,
+		       gint         end_pos)
+{
+  gtk_entry_queue_draw (GTK_ENTRY(editable));
+}
+
+static gchar *    
+gtk_entry_get_chars      (GtkEditable   *editable,
+			  gint           start_pos,
+			  gint           end_pos)
+{
+  GtkEntry *entry;
+  
+  g_return_val_if_fail (editable != NULL, NULL);
+  g_return_val_if_fail (GTK_IS_ENTRY (editable), NULL);
+
+  entry = GTK_ENTRY (editable);
+
+  if (end_pos < 0)
+    end_pos = entry->text_length;
+
+  start_pos = MIN(entry->text_length, start_pos);
+  end_pos = MIN(entry->text_length, end_pos);
+
+  if (start_pos <= end_pos)
+    {
+      guchar *mbstr;
+      if (entry->use_wchar)
+	{
+	  GdkWChar ch;
+	  if (end_pos >= entry->text_size)
+	    gtk_entry_grow_text(entry);
+	  ch = entry->text[end_pos];
+	  entry->text[end_pos] = 0;
+	  mbstr = gdk_wcstombs (entry->text + start_pos);
+	  entry->text[end_pos] = ch;
+	  return (gchar *)mbstr;
+	}
+      else
+	{
+	  gint i;
+	  mbstr = g_new (gchar, end_pos - start_pos + 1);
+	  for (i=0; i<end_pos-start_pos; i++)
+	    mbstr[i] = entry->text[start_pos + i];
+	  mbstr[i] = 0;
+	  return (gchar *)mbstr;
+	}
+    }
+  else
+    return NULL;
+}
+
+static void 
+gtk_entry_move_cursor (GtkEditable *editable,
+		       gint         x,
+		       gint         y)
+{
+  GtkEntry *entry;
+  entry = GTK_ENTRY (editable);
+
+  /* Horizontal motion */
+  if ((gint)editable->current_pos < -x)
+    editable->current_pos = 0;
+  else if (editable->current_pos + x > entry->text_length)
+    editable->current_pos = entry->text_length;
+  else
+    editable->current_pos += x;
+
+  /* Ignore vertical motion */
+}
+
+static void
+gtk_move_forward_character (GtkEntry *entry)
+{
+  gtk_entry_move_cursor (GTK_EDITABLE (entry), 1, 0);
+}
+
+static void
+gtk_move_backward_character (GtkEntry *entry)
+{
+  gtk_entry_move_cursor (GTK_EDITABLE (entry), -1, 0);
+}
+
+static void 
+gtk_entry_move_word (GtkEditable *editable,
+		     gint         n)
+{
+  while (n > 0)
+    {
+      gtk_move_forward_word (GTK_ENTRY (editable));
+      n--;
+    }
+  while (n < 0)
+    {
+      gtk_move_backward_word (GTK_ENTRY (editable));
+      n++;
+    }
+}
+
+static void
+gtk_move_forward_word (GtkEntry *entry)
+{
+  GtkEditable *editable;
+  GdkWChar *text;
+  gint i;
+
+  editable = GTK_EDITABLE (entry);
+
+  /* Prevent any leak of information */
+  if (!editable->visible)
+    {
+      editable->current_pos = entry->text_length;
+      return;
+    }
+
+  if (entry->text && (editable->current_pos < entry->text_length))
+    {
+      text = entry->text;
+      i = editable->current_pos;
+	  
+      if ((entry->use_wchar) ? (!gdk_iswalnum (text[i])) : (!isalnum (text[i])))
+	for (; i < entry->text_length; i++)
+	  {
+	    if ((entry->use_wchar) ? gdk_iswalnum (text[i]) : isalnum (text[i]))
+	      break;
+	  }
+
+      for (; i < entry->text_length; i++)
+	{
+	  if ((entry->use_wchar) ? (!gdk_iswalnum (text[i])) : (!isalnum (text[i])))
+	    break;
+	}
+
+      editable->current_pos = i;
+    }
+}
+
+static void
+gtk_move_backward_word (GtkEntry *entry)
+{
+  GtkEditable *editable;
+  GdkWChar *text;
+  gint i;
+
+  editable = GTK_EDITABLE (entry);
+
+  /* Prevent any leak of information */
+  if (!editable->visible)
+    {
+      editable->current_pos = 0;
+      return;
+    }
+
+  if (entry->text && editable->current_pos > 0)
+    {
+      text = entry->text;
+      i = editable->current_pos - 1;
+      if ((entry->use_wchar) ? (!gdk_iswalnum (text[i])) : (!isalnum (text[i])))
+	for (; i >= 0; i--)
+	  {
+	    if ((entry->use_wchar) ? gdk_iswalnum (text[i]) : isalnum (text[i]))
+	      break;
+	  }
+      for (; i >= 0; i--)
+	{
+	  if ((entry->use_wchar) ? (!gdk_iswalnum (text[i])) : (!isalnum (text[i])))
+	    {
+	      i++;
+	      break;
+	    }
+	}
+	  
+      if (i < 0)
+	i = 0;
+	  
+      editable->current_pos = i;
+    }
+}
+
+static void
+gtk_entry_move_to_column (GtkEditable *editable, gint column)
+{
+  GtkEntry *entry;
+
+  entry = GTK_ENTRY (editable);
+  
+  if (column < 0 || column > entry->text_length)
+    editable->current_pos = entry->text_length;
+  else
+    editable->current_pos = column;
+}
+
+static void
+gtk_move_beginning_of_line (GtkEntry *entry)
+{
+  gtk_entry_move_to_column (GTK_EDITABLE (entry), 0);
+}
+
+static void
+gtk_move_end_of_line (GtkEntry *entry)
+{
+  gtk_entry_move_to_column (GTK_EDITABLE (entry), -1);
+}
+
+static void
+gtk_entry_kill_char (GtkEditable *editable,
+		     gint         direction)
+{
+  if (editable->selection_start_pos != editable->selection_end_pos)
+    gtk_editable_delete_selection (editable);
+  else
+    {
+      gint old_pos = editable->current_pos;
+      if (direction >= 0)
+	{
+	  gtk_entry_move_cursor (editable, 1, 0);
+	  gtk_editable_delete_text (editable, old_pos, editable->current_pos);
+	}
+      else
+	{
+	  gtk_entry_move_cursor (editable, -1, 0);
+	  gtk_editable_delete_text (editable, editable->current_pos, old_pos);
+	}
+    }
+}
+
+static void
+gtk_delete_forward_character (GtkEntry *entry)
+{
+  gtk_entry_kill_char (GTK_EDITABLE (entry), 1);
+}
+
+static void
+gtk_delete_backward_character (GtkEntry *entry)
+{
+  gtk_entry_kill_char (GTK_EDITABLE (entry), -1);
+}
+
+static void
+gtk_entry_kill_word (GtkEditable *editable,
+		     gint         direction)
+{
+  if (editable->selection_start_pos != editable->selection_end_pos)
+    gtk_editable_delete_selection (editable);
+  else
+    {
+      gint old_pos = editable->current_pos;
+      if (direction >= 0)
+	{
+	  gtk_entry_move_word (editable, 1);
+	  gtk_editable_delete_text (editable, old_pos, editable->current_pos);
+	}
+      else
+	{
+	  gtk_entry_move_word (editable, -1);
+	  gtk_editable_delete_text (editable, editable->current_pos, old_pos);
+	}
+    }
+}
+
+static void
+gtk_delete_forward_word (GtkEntry *entry)
+{
+  gtk_entry_kill_word (GTK_EDITABLE (entry), 1);
+}
+
+static void
+gtk_delete_backward_word (GtkEntry *entry)
+{
+  gtk_entry_kill_word (GTK_EDITABLE (entry), -1);
+}
+
+static void
+gtk_entry_kill_line (GtkEditable *editable,
+		     gint         direction)
+{
+  gint old_pos = editable->current_pos;
+  if (direction >= 0)
+    {
+      gtk_entry_move_to_column (editable, -1);
+      gtk_editable_delete_text (editable, old_pos, editable->current_pos);
+    }
+  else
+    {
+      gtk_entry_move_to_column (editable, 0);
+      gtk_editable_delete_text (editable, editable->current_pos, old_pos);
+    }
+}
+
+static void
+gtk_delete_line (GtkEntry *entry)
+{
+  gtk_entry_move_to_column (GTK_EDITABLE (entry), 0);
+  gtk_entry_kill_line (GTK_EDITABLE (entry), 1);
+}
+
+static void
+gtk_delete_to_line_end (GtkEntry *entry)
+{
+  gtk_editable_delete_text (GTK_EDITABLE(entry), GTK_EDITABLE(entry)->current_pos, entry->text_length);
+}
+
+static void
+gtk_select_word (GtkEntry *entry,
+		 guint32   time)
+{
+  GtkEditable *editable;
+  gint start_pos;
+  gint end_pos;
+
+  editable = GTK_EDITABLE (entry);
+
+  gtk_move_backward_word (entry);
+  start_pos = editable->current_pos;
+
+  gtk_move_forward_word (entry);
+  end_pos = editable->current_pos;
+
+  editable->has_selection = TRUE;
+  gtk_entry_set_selection (editable, start_pos, end_pos);
+  gtk_editable_claim_selection (editable, start_pos != end_pos, time);
+}
+
+static void
+gtk_select_line (GtkEntry *entry,
+		 guint32   time)
+{
+  GtkEditable *editable;
+
+  editable = GTK_EDITABLE (entry);
+
+  editable->has_selection = TRUE;
+  gtk_entry_set_selection (editable, 0, entry->text_length);
+  gtk_editable_claim_selection (editable, entry->text_length != 0, time);
+
+  editable->current_pos = editable->selection_end_pos;
+}
+
+static void 
+gtk_entry_set_selection (GtkEditable       *editable,
+			 gint               start,
+			 gint               end)
+{
+  gint length = GTK_ENTRY (editable)->text_length;
+  
+  g_return_if_fail (editable != NULL);
+  g_return_if_fail (GTK_IS_ENTRY (editable));
+
+  if (end < 0)
+    end = length;
+  
+  editable->selection_start_pos = CLAMP (start, 0, length);
+  editable->selection_end_pos = MIN (end, length);
+
+  gtk_entry_queue_draw (GTK_ENTRY (editable));
+}
+
+void       
+gtk_entry_select_region  (GtkEntry       *entry,
+			  gint            start,
+			  gint            end)
+{
+  gtk_editable_select_region (GTK_EDITABLE (entry), start, end);
+}
+
+void
+gtk_entry_set_max_length (GtkEntry     *entry,
+                          guint16       max)
+{
+  g_return_if_fail (entry != NULL);
+  g_return_if_fail (GTK_IS_ENTRY (entry));
+
+  if (max && entry->text_length > max)
+  	gtk_editable_delete_text(GTK_EDITABLE(entry), max, -1);
+  entry->text_max_length = max;
+}
+
+#ifdef USE_XIM
+static void
+gtk_entry_update_ic_attr (GtkWidget *widget)
+{
+  GtkEditable *editable = (GtkEditable *) widget;
+  GdkICAttributesType mask = 0;
+
+  if (editable->ic == NULL)
+    return;
+
+  gdk_ic_get_attr (editable->ic, editable->ic_attr,
+		   GDK_IC_PREEDIT_FOREGROUND |
+		   GDK_IC_PREEDIT_BACKGROUND |
+		   GDK_IC_PREEDIT_FONTSET);
+
+  if (editable->ic_attr->preedit_foreground.pixel != 
+      widget->style->fg[GTK_STATE_NORMAL].pixel)
+    {
+      mask |= GDK_IC_PREEDIT_FOREGROUND;
+      editable->ic_attr->preedit_foreground
+	= widget->style->fg[GTK_STATE_NORMAL];
+    }
+  if (editable->ic_attr->preedit_background.pixel != 
+      widget->style->base[GTK_STATE_NORMAL].pixel)
+    {
+      mask |= GDK_IC_PREEDIT_BACKGROUND;
+      editable->ic_attr->preedit_background
+	= widget->style->base[GTK_STATE_NORMAL];
+    }
+  if ((gdk_ic_get_style (editable->ic) & GDK_IM_PREEDIT_POSITION) && 
+      widget->style->font != NULL &&
+      widget->style->font->type == GDK_FONT_FONTSET &&
+      !gdk_font_equal (editable->ic_attr->preedit_fontset,
+		       widget->style->font))
+    {
+      mask |= GDK_IC_PREEDIT_FONTSET;
+      editable->ic_attr->preedit_fontset = widget->style->font;
+    }
+  
+  if (mask)
+    gdk_ic_set_attr (editable->ic, editable->ic_attr, mask);
+}
+#endif /* USE_XIM */
+    			  
+static void 
+gtk_entry_style_set	(GtkWidget      *widget,
+			 GtkStyle       *previous_style)
+{
+  GtkEntry *entry;
+  gint scroll_char;
+
+  g_return_if_fail (widget != NULL);
+  g_return_if_fail (GTK_IS_ENTRY (widget));
+
+  if (previous_style && GTK_WIDGET_REALIZED (widget))
+    {
+      entry = GTK_ENTRY (widget);
+  
+      scroll_char = gtk_entry_find_position (entry, entry->scroll_offset);
+      gtk_entry_recompute_offsets (GTK_ENTRY (widget));
+      entry->scroll_offset = entry->char_offset[scroll_char];
+      entry_adjust_scroll (entry);
+
+      gdk_window_set_background (widget->window, &widget->style->base[GTK_WIDGET_STATE (widget)]);
+      gdk_window_set_background (entry->text_area, &widget->style->base[GTK_WIDGET_STATE (widget)]);
+
+#ifdef USE_XIM
+      gtk_entry_update_ic_attr (widget);
+#endif
+    }
+}
+
+static void
+gtk_entry_state_changed (GtkWidget      *widget,
+			 GtkStateType    previous_state)
+{
+  g_return_if_fail (widget != NULL);
+  g_return_if_fail (GTK_IS_ENTRY (widget));
+
+  if (GTK_WIDGET_REALIZED (widget))
+    {
+      gdk_window_set_background (widget->window, &widget->style->base[GTK_WIDGET_STATE (widget)]);
+      gdk_window_set_background (GTK_ENTRY (widget)->text_area, &widget->style->base[GTK_WIDGET_STATE (widget)]);
+
+#ifdef USE_XIM
+      gtk_entry_update_ic_attr (widget);
+#endif
+    }
+
+  if (GTK_WIDGET_DRAWABLE (widget))
+    gtk_widget_queue_clear(widget);
+}
diff -ruN gtk+-1.2.10/gtk/gtklabel.c gtk-n/gtk/gtklabel.c
--- gtk+-1.2.10/gtk/gtklabel.c	Mon Apr  2 05:12:38 2001
+++ gtk-n/gtk/gtklabel.c	Thu Jan 31 08:57:14 2002
@@ -56,6 +56,7 @@
   GtkLabelWord *next;
   gint uline_y;
   GtkLabelULine *uline;
+  gboolean paragraph_break;
 };
 
 struct _GtkLabelULine
@@ -396,6 +397,7 @@
   word->beginning = NULL;
   word->next = NULL;
   word->uline = NULL;
+  word->paragraph_break = FALSE;
 
   return word;
 }
@@ -441,6 +443,7 @@
       if (str == label->label_wc || str[-1] == '\n')
 	{
 	  /* Paragraph break */
+	  word->paragraph_break = TRUE;
 	  word->space = 0;
 	  
 	  max_line_width = MAX (line_width, max_line_width);
@@ -488,6 +491,7 @@
     {
       word = gtk_label_word_alloc ();
       
+      word->paragraph_break = TRUE;
       word->space = 0;
       word->beginning = str;
       word->length = 0;
@@ -500,6 +504,16 @@
   return MAX (line_width, max_line_width);
 }
 
+static gboolean
+is_ideogram (GdkWChar wc)
+{
+    if (gdk_iswalpha (wc) && (!gdk_iswupper (wc) && !gdk_iswlower (wc)))
+	return TRUE;
+    
+    return !(gdk_iswspace (wc) || gdk_iswalnum (wc) ||
+	     gdk_iswpunct (wc) || gdk_iswcntrl (wc));
+}
+
 /* this needs to handle white space better. */
 static gint
 gtk_label_split_text_wrapped (GtkLabel *label)
@@ -526,6 +540,7 @@
       if (str == label->label_wc || str[-1] == '\n')
 	{
 	  /* Paragraph break */
+	  word->paragraph_break = TRUE;
 	  word->space = 0;
 	  
 	  max_line_width = MAX (line_width, max_line_width);
@@ -546,24 +561,30 @@
 	  else
 	    word->space = space_width * nspaces;
 	}
-      else
+      else if (gdk_iswspace (str[-1]))
 	{
 	  /* Regular inter-word space */
 	  word->space = space_width;
 	}
+      else
+	{
+	  word->space = 0;
+	}
       
       word->beginning = str;
       word->length = 0;
       p = word->beginning;
       while (*p && !gdk_iswspace (*p))
 	{
+	  if (word->length > 0 && (is_ideogram (p[-1]) || is_ideogram (*p)))
+	    break;
 	  word->length++;
 	  p++;
 	}
       word->width = gdk_text_width_wc (GTK_WIDGET (label)->style->font, str, word->length);
       
       str += word->length;
-      if (*str)
+      if (*str && gdk_iswspace (*str))
 	str++;
       
       line_width += word->space + word->width;
@@ -600,7 +621,7 @@
   width = 0;
   for (word = label->words; word; word = word->next)
     {
-      if (word->space == 0
+      if (word->paragraph_break
 	  || (line_width
 	      && (line_width >= min_width
 		  || line_width + word->width + word->space > max_width)))
@@ -716,7 +737,8 @@
   GtkLabelWord *word, *line, *next_line;
   GtkWidget *widget;
   gchar *ptrn;
-  gint x, y, space, extra_width, add_space, baseline_skip;
+  gint x, y, space, num_words, extra_width, add_space, baseline_skip;
+  gboolean deliver_equivalently;
   
   g_return_if_fail (label->wrap);
   
@@ -724,20 +746,24 @@
   y = 0;
   baseline_skip = (GTK_WIDGET (label)->style->font->ascent +
 		   GTK_WIDGET (label)->style->font->descent + 1);
+  deliver_equivalently = FALSE;
   
   for (line = label->words; line != 0; line = next_line)
     {
-      space = 0;
+      space = num_words = 0;
       extra_width = max_line_width - line->width;
       
       for (next_line = line->next; next_line; next_line = next_line->next)
 	{
-	  if (next_line->space == 0)
+	  if (next_line->paragraph_break)
 	    break;		/* New paragraph */
 	  if (next_line->space + next_line->width > extra_width)
 	    break;
+	  if (next_line->space == 0)
+	    deliver_equivalently = TRUE; /* An ideogram is found. */
 	  extra_width -= next_line->space + next_line->width;
 	  space += next_line->space;
+	  num_words++;
 	}
       
       line->x = 0;
@@ -747,14 +773,18 @@
       
       for (word = line->next; word != next_line; word = word->next)
 	{
-	  if (next_line && next_line->space)
+	  if (next_line && !next_line->paragraph_break &&
+	      label->jtype == GTK_JUSTIFY_FILL &&
+	      (deliver_equivalently ? num_words : space) > 0)
 	    {
-	      /* Not last line of paragraph --- fill line if needed */
-	      if (label->jtype == GTK_JUSTIFY_FILL) {
+	      /* Not last line of paragraph --- fill line */
+	      if (deliver_equivalently)
+		add_space = (extra_width + num_words / 2) / num_words;
+	      else
 		add_space = (extra_width * word->space + space / 2) / space;
-		extra_width -= add_space;
-		space -= word->space;
-	      }
+	      extra_width -= add_space;
+	      space -= word->space;
+	      num_words--;
 	    }
 	  
 	  word->x = x + word->space + add_space;
@@ -925,7 +955,7 @@
 
       for (word = label->words; word; word = word->next)
 	{
-	  gchar save = word->beginning[word->length];
+	  GdkWChar save = word->beginning[word->length];
 	  word->beginning[word->length] = '\0';
 	  gtk_label_paint_word (label, x, y, word, &event->area);
 	  word->beginning[word->length] = save;
diff -ruN gtk+-1.2.10/gtk/gtkmenushell.c gtk-n/gtk/gtkmenushell.c
--- gtk+-1.2.10/gtk/gtkmenushell.c	Mon Mar  5 22:38:05 2001
+++ gtk-n/gtk/gtkmenushell.c	Thu Jan 31 08:57:05 2002
@@ -258,6 +258,11 @@
 				GTK_TYPE_BOOL,
 				TRUE);
   gtk_binding_entry_add_signal (binding_set,
+				GDK_KP_Enter, 0,
+				"activate_current", 1,
+				GTK_TYPE_BOOL,
+				TRUE);
+  gtk_binding_entry_add_signal (binding_set,
 				GDK_space, 0,
 				"activate_current", 1,
 				GTK_TYPE_BOOL,
diff -ruN gtk+-1.2.10/gtk/gtknotebook.c gtk-n/gtk/gtknotebook.c
--- gtk+-1.2.10/gtk/gtknotebook.c	Wed Jan 31 00:27:26 2001
+++ gtk-n/gtk/gtknotebook.c	Thu Jan 31 08:57:05 2002
@@ -1369,6 +1369,7 @@
 	gtk_notebook_switch_focus_tab (notebook, list);
       return TRUE;
     case GDK_Return:
+    case GDK_KP_Enter:
     case GDK_space:
       gtk_notebook_page_select (GTK_NOTEBOOK (widget));
       return TRUE;
diff -ruN gtk+-1.2.10/gtk/gtkrc.c gtk-n/gtk/gtkrc.c
--- gtk+-1.2.10/gtk/gtkrc.c	Thu Mar 15 19:41:40 2001
+++ gtk-n/gtk/gtkrc.c	Thu Jan 31 08:56:58 2002
@@ -33,6 +33,7 @@
 #include <string.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <langinfo.h>
 
 #include "gtkrc.h"
 #include "gtkbindings.h"
@@ -440,7 +441,7 @@
 void
 gtk_rc_init (void)
 {
-  static gchar *locale_suffixes[3];
+  static gchar *locale_suffixes[8];
   static gint n_locale_suffixes = 0;
 
   gint i, j;
@@ -449,9 +450,7 @@
 
   if (!initted)
     {
-      gint length;
-      
-      char *locale = setlocale (LC_CTYPE, NULL);
+      char *locale = g_strdup (setlocale (LC_CTYPE, NULL));
       char *p;
       
       initted = TRUE;
@@ -470,39 +469,84 @@
 	   * We normalize the charset into a standard form,
 	   * which has all '-' and '_' characters removed,
 	   * and is lowercase.
+	   *
+	   * the search is done in that order:
+	   * gtkrc.ll_cc.lowercasecodeset
+	   * gtkrc.ll_cc.normalizedcodeset
+	   * gtkrc.ll.lowercasecodeset
+	   * gtkrc.ll.normalizedcodeset
+	   * gtkrc.lowercasecodeset
+	   * gtkrc.normalizedcodeset
+	   * gtkrc.ll_cc
+	   * gtkrc.ll
+	   * 
 	   */
-	  gchar *normalized_locale;
+	  char *codeset = NULL;
+	  char *normalized_codeset = NULL;
+	  char *cc = NULL;
+	  char *ll;
 
 	  p = strchr (locale, '@');
-	  length = p ? (p -locale) : strlen (locale);
+	  if (p)
+	    *p = '\0';
 
+	  codeset = nl_langinfo (CODESET);
+	  
 	  p = strchr (locale, '.');
+	  if (!codeset && p)
+	    codeset = p + 1;
 	  if (p)
+	    *p = '\0';
+	  
+	  if (codeset)
 	    {
-	      gchar *tmp1 = g_strndup (locale, p - locale + 1);
-	      gchar *tmp2 = _gtk_normalize_codeset (p + 1, length - (p - locale + 1));
+	      codeset = g_strdup (codeset);
 	      
-	      normalized_locale = g_strconcat (tmp1, tmp2, NULL);
-	      g_free (tmp1);
-	      g_free (tmp2);
-						 
-	      locale_suffixes[n_locale_suffixes++] = g_strdup (normalized_locale);
-	      length = p - locale;
+	      p = codeset;
+	      while (*p)
+		{
+		  /* tolower not used, because some locales are not
+		   * compatible with C locale in lowercasing ascii
+		   */
+		  if (*p >= 'A' && *p <= 'Z')
+		    *p = (*p) - 'A' + 'a';
+		  p++;
+		}
+	      
+	      normalized_codeset = _gtk_normalize_codeset(codeset, strlen (codeset));
+	      if (strcmp (normalized_codeset, codeset) == 0)
+		normalized_codeset = NULL;
 	    }
-	  else
-	    normalized_locale = g_strndup (locale, length);
 	  
-	  p = strchr (normalized_locale, '_');
+	  p = strchr (locale, '_');
 	  if (p)
 	    {
-	      locale_suffixes[n_locale_suffixes++] = g_strndup (normalized_locale, length);
-	      length = p - normalized_locale;
+	      cc = p + 1;
+	      *p = '\0';
 	    }
-	  
-	  locale_suffixes[n_locale_suffixes++] = g_strndup (normalized_locale, length);
 
-	  g_free (normalized_locale);
+	  ll = locale;	
+	
+	  if (cc && codeset)
+	    locale_suffixes[n_locale_suffixes++] = g_strconcat (ll, "_", cc, ".", codeset, NULL);
+          if (cc && normalized_codeset)
+	    locale_suffixes[n_locale_suffixes++] = g_strconcat (ll, "_", cc, ".", normalized_codeset, NULL);
+	  if (codeset)
+            locale_suffixes[n_locale_suffixes++] = g_strconcat (ll, ".", codeset, NULL);
+          if (normalized_codeset)
+	    locale_suffixes[n_locale_suffixes++] = g_strconcat (ll, ".", normalized_codeset, NULL);
+	  if (codeset)
+	    locale_suffixes[n_locale_suffixes++] = g_strdup (codeset);
+	  if (normalized_codeset)
+	    locale_suffixes[n_locale_suffixes++] = g_strdup (normalized_codeset);
+	  if (cc)
+            locale_suffixes[n_locale_suffixes++] = g_strconcat (ll, "_", cc, NULL);
+	  locale_suffixes[n_locale_suffixes++] = g_strdup (ll);
+
+	  g_free (codeset);
 	}
+
+      g_free (locale);
     }
   
   i = 0;
diff -ruN gtk+-1.2.10/gtk/gtkrc.iso885913 gtk-n/gtk/gtkrc.iso885913
--- gtk+-1.2.10/gtk/gtkrc.iso885913	Thu Jan  1 01:00:00 1970
+++ gtk-n/gtk/gtkrc.iso885913	Thu Jan 31 08:56:58 2002
@@ -0,0 +1,7 @@
+style "gtk-default-iso-8859-13" {
+       fontset = "-*-helvetica-medium-r-normal--12-*-*-*-*-*-iso8859-1,\
+                  -*-arial-medium-r-normal--12-*-*-*-*-*-iso8859-1,\
+		  -*-helvetica-medium-r-normal--12-*-*-*-*-*-iso8859-13,\
+		  -*-arial-medium-r-normal--12-*-*-*-*-*-iso8859-13,*-r-*"
+}
+class "GtkWidget" style "gtk-default-iso-8859-13"
diff -ruN gtk+-1.2.10/gtk/gtkrc.iso885914 gtk-n/gtk/gtkrc.iso885914
--- gtk+-1.2.10/gtk/gtkrc.iso885914	Thu Jan  1 01:00:00 1970
+++ gtk-n/gtk/gtkrc.iso885914	Thu Jan 31 08:56:58 2002
@@ -0,0 +1,8 @@
+style "gtk-default-iso-8859-14" {
+       fontset = "-*-helvetica-medium-r-normal--12-*-*-*-*-*-iso8859-1,\
+                  -*-arial-medium-r-normal--12-*-*-*-*-*-iso8859-1,\
+		  -*-helvetica-medium-r-normal--12-*-*-*-*-*-iso8859-14,\
+		  -*-arial-medium-r-normal--12-*-*-*-*-*-iso8859-14,*-r-*"
+}
+class "GtkWidget" style "gtk-default-iso-8859-14"
+
diff -ruN gtk+-1.2.10/gtk/gtkrc.iso885915 gtk-n/gtk/gtkrc.iso885915
--- gtk+-1.2.10/gtk/gtkrc.iso885915	Thu Jan  1 01:00:00 1970
+++ gtk-n/gtk/gtkrc.iso885915	Thu Jan 31 08:56:58 2002
@@ -0,0 +1,8 @@
+style "gtk-default-iso-8859-15" {
+       fontset = "-*-helvetica-medium-r-normal--12-*-*-*-*-*-iso8859-1,\
+                  -*-arial-medium-r-normal--12-*-*-*-*-*-iso8859-1,\
+		  -*-helvetica-medium-r-normal--12-*-*-*-*-*-iso8859-15,\
+		  -*-arial-medium-r-normal--12-*-*-*-*-*-iso8859-15,*-r-*"
+}
+class "GtkWidget" style "gtk-default-iso-8859-15"
+
diff -ruN gtk+-1.2.10/gtk/gtkrc.iso88592 gtk-n/gtk/gtkrc.iso88592
--- gtk+-1.2.10/gtk/gtkrc.iso88592	Thu Jan  1 01:00:00 1970
+++ gtk-n/gtk/gtkrc.iso88592	Thu Jan 31 08:56:58 2002
@@ -0,0 +1,14 @@
+#$(gtkconfigdir)/gtkrc.iso-8859-2
+#
+# This file defines the fontsets for iso-8859-2 encoding
+# make symliks or hardlinks to gtkrc.$LANG if your language uses iso-8859-2
+# and a gtkrc.$LANG doesn't exist yet.
+
+style  "gtk-default-iso-8859-2" {
+       fontset = "-*-helvetica-medium-r-normal--12-*-*-*-*-*-iso8859-1,\
+                  -*-arial-medium-r-normal--12-*-*-*-*-*-iso8859-1,\
+		  -*-helvetica-medium-r-normal--12-*-*-*-*-*-iso8859-2,\
+		  -*-arial-medium-r-normal--12-*-*-*-*-*-iso8859-2,*-r-*"
+}
+class "GtkWidget" style "gtk-default-iso-8859-2"
+
diff -ruN gtk+-1.2.10/gtk/gtkrc.iso88593 gtk-n/gtk/gtkrc.iso88593
--- gtk+-1.2.10/gtk/gtkrc.iso88593	Thu Jan  1 01:00:00 1970
+++ gtk-n/gtk/gtkrc.iso88593	Thu Jan 31 08:56:58 2002
@@ -0,0 +1,8 @@
+style "gtk-default-iso-8859-3" {
+       fontset = "-*-helvetica-medium-r-normal--12-*-*-*-*-*-iso8859-1,\
+                  -*-arial-medium-r-normal--12-*-*-*-*-*-iso8859-1,\
+		  -*-helvetica-medium-r-normal--12-*-*-*-*-*-iso8859-3,\
+		  -*-arial-medium-r-normal--12-*-*-*-*-*-iso8859-3,*-r-*"
+}
+class "GtkWidget" style "gtk-default-iso-8859-3"
+
diff -ruN gtk+-1.2.10/gtk/gtkrc.iso88595 gtk-n/gtk/gtkrc.iso88595
--- gtk+-1.2.10/gtk/gtkrc.iso88595	Thu Jan  1 01:00:00 1970
+++ gtk-n/gtk/gtkrc.iso88595	Thu Jan 31 08:56:58 2002
@@ -0,0 +1,14 @@
+#$(gtkconfigdir)/gtkrc.iso-8859-5
+#
+# This file defines the fontsets for iso-8859-5 encoding
+# make symliks or hardlinks to gtkrc.$LANG if your language uses iso-8859-5
+# and a gtkrc.$LANG doesn't exist yet.
+
+style "gtk-default-iso-8859-5" {
+       fontset = "-*-helvetica-medium-r-normal--12-*-*-*-*-*-iso8859-1,\
+                  -*-arial-medium-r-normal--12-*-*-*-*-*-iso8859-1,\
+		  -*-helvetica-medium-r-normal--12-*-*-*-*-*-iso8859-5,\
+		  -*-arial-medium-r-normal--12-*-*-*-*-*-iso8859-5,*-r-*"
+}
+class "GtkWidget" style "gtk-default-iso-8859-5"
+
diff -ruN gtk+-1.2.10/gtk/gtkrc.iso88597 gtk-n/gtk/gtkrc.iso88597
--- gtk+-1.2.10/gtk/gtkrc.iso88597	Thu Jan  1 01:00:00 1970
+++ gtk-n/gtk/gtkrc.iso88597	Thu Jan 31 08:56:58 2002
@@ -0,0 +1,8 @@
+style "gtk-default-iso-8859-7" {
+       fontset = "-*-helvetica-medium-r-normal--12-*-*-*-*-*-iso8859-1,\
+		  -*-arial-medium-r-normal--12-*-*-*-*-*-iso8859-1,\
+		  -*-helvetica-medium-r-normal--12-*-*-*-*-*-iso8859-7,\
+		  -*-arial-medium-r-normal--12-*-*-*-*-*-iso8859-7,*-r-*"
+}
+class "GtkWidget" style "gtk-default-iso-8859-7"
+
diff -ruN gtk+-1.2.10/gtk/gtkrc.iso88599 gtk-n/gtk/gtkrc.iso88599
--- gtk+-1.2.10/gtk/gtkrc.iso88599	Thu Jan  1 01:00:00 1970
+++ gtk-n/gtk/gtkrc.iso88599	Thu Jan 31 08:56:58 2002
@@ -0,0 +1,8 @@
+style "gtk-default-iso-8859-9" {
+       fontset = "-*-helvetica-medium-r-normal--12-*-*-*-*-*-iso8859-1,\
+                  -*-arial-medium-r-normal--12-*-*-*-*-*-iso8859-1,\
+		  -*-helvetica-medium-r-normal--12-*-*-*-*-*-iso8859-9,\
+		  -*-arial-medium-r-normal--12-*-*-*-*-*-iso8859-9,*-r-*"
+}
+class "GtkWidget" style "gtk-default-iso-8859-9"
+
diff -ruN gtk+-1.2.10/gtk/gtkrc.utf8 gtk-n/gtk/gtkrc.utf8
--- gtk+-1.2.10/gtk/gtkrc.utf8	Thu Jan  1 01:00:00 1970
+++ gtk-n/gtk/gtkrc.utf8	Thu Jan 31 08:56:58 2002
@@ -0,0 +1,7 @@
+style "default-text" {
+       fontset = "-*-helvetica-medium-r-normal--*-120-*-*-*-*-*-*"
+
+}
+
+class "GtkWidget" style "default-text"
+
diff -ruN gtk+-1.2.10/gtk/gtkstyle.c gtk-n/gtk/gtkstyle.c
--- gtk+-1.2.10/gtk/gtkstyle.c	Tue Feb 20 17:46:58 2001
+++ gtk-n/gtk/gtkstyle.c	Thu Jan 31 08:56:36 2002
@@ -348,8 +348,9 @@
       new_style->bg[i] = style->bg[i];
       new_style->text[i] = style->text[i];
       new_style->base[i] = style->base[i];
-      
-      new_style->bg_pixmap[i] = style->bg_pixmap[i];
+
+      if (style->bg_pixmap[i] && !(style->rc_style && style->rc_style->bg_pixmap_name[i]))
+	new_style->bg_pixmap[i] = gdk_pixmap_ref (style->bg_pixmap[i]);
     }
   
   gdk_font_unref (new_style->font);
diff -ruN gtk+-1.2.10/gtk/gtktext.c gtk-n/gtk/gtktext.c
--- gtk+-1.2.10/gtk/gtktext.c	Thu Mar 15 21:15:12 2001
+++ gtk-n/gtk/gtktext.c	Thu Jan 31 08:57:05 2002
@@ -101,6 +101,13 @@
   ARG_WORD_WRAP
 };
 
+typedef enum {
+  CHAR_CLASS_SPACE,
+  CHAR_CLASS_ALNUM,
+  CHAR_CLASS_IDEOGRAM,
+  CHAR_CLASS_OTHERS     /* punct, cntrl */
+} CharClass;
+
 typedef struct _TextProperty          TextProperty;
 typedef struct _TabStopMark           TabStopMark;
 typedef struct _PrevTabCont           PrevTabCont;
@@ -300,6 +307,8 @@
 				    const GtkPropertyMark *mark,
 				    const PrevTabCont *tab_cont,
 				    PrevTabCont *next_cont);
+static void find_word_wrap_position (GtkText* text, LineParams *lp);
+static CharClass char_class (GtkText* text, guint index);
 static void recompute_geometry (GtkText* text);
 static void insert_expose (GtkText* text, guint old_pixels, gint nchars, guint new_line_count);
 static void delete_expose (GtkText* text,
@@ -2046,6 +2055,7 @@
 	case GDK_Up:        scroll_int (text, -KEY_SCROLL_PIXELS); break;
 	case GDK_Down:      scroll_int (text, +KEY_SCROLL_PIXELS); break;
 	case GDK_Return:
+	case GDK_KP_Enter:
 	  if (event->state & GDK_CONTROL_MASK)
 	    gtk_signal_emit_by_name (GTK_OBJECT (text), "activate");
 	  else
@@ -2152,6 +2162,7 @@
 	  gtk_editable_insert_text (editable, "\t", 1, &position);
 	  break;
 	case GDK_Return:
+	case GDK_KP_Enter:
 	  if (event->state & GDK_CONTROL_MASK)
 	    gtk_signal_emit_by_name (GTK_OBJECT (text), "activate");
 	  else
@@ -4111,27 +4122,21 @@
   
   undraw_cursor (text, FALSE);
   
-  if (text->use_wchar)
+  while (!LAST_INDEX (text, text->cursor_mark))
     {
-      while (!LAST_INDEX (text, text->cursor_mark) && 
-	     !gdk_iswalnum (GTK_TEXT_INDEX(text, text->cursor_mark.index)))
-	advance_mark (&text->cursor_mark);
-      
-      while (!LAST_INDEX (text, text->cursor_mark) && 
-	     gdk_iswalnum (GTK_TEXT_INDEX(text, text->cursor_mark.index)))
-	advance_mark (&text->cursor_mark);
+      CharClass cc = char_class (text, text->cursor_mark.index);
+      if (cc == CHAR_CLASS_ALNUM || cc == CHAR_CLASS_IDEOGRAM)
+	break;
+      advance_mark (&text->cursor_mark);
     }
-  else
+  while (!LAST_INDEX (text, text->cursor_mark))
     {
-      while (!LAST_INDEX (text, text->cursor_mark) && 
-	     !isalnum (GTK_TEXT_INDEX(text, text->cursor_mark.index)))
-	advance_mark (&text->cursor_mark);
-      
-      while (!LAST_INDEX (text, text->cursor_mark) && 
-	     isalnum (GTK_TEXT_INDEX(text, text->cursor_mark.index)))
-	advance_mark (&text->cursor_mark);
+      CharClass cc = char_class (text, text->cursor_mark.index);
+      if (cc != CHAR_CLASS_ALNUM && cc != CHAR_CLASS_IDEOGRAM)
+	break;
+      advance_mark (&text->cursor_mark);
     }
-  
+
   find_cursor (text, TRUE);
   draw_cursor (text, FALSE);
 }
@@ -4143,25 +4148,19 @@
   
   undraw_cursor (text, FALSE);
   
-  if (text->use_wchar)
+  while (text->cursor_mark.index > 0)
     {
-      while ((text->cursor_mark.index > 0) &&
-	     !gdk_iswalnum (GTK_TEXT_INDEX(text, text->cursor_mark.index-1)))
-	decrement_mark (&text->cursor_mark);
-      
-      while ((text->cursor_mark.index > 0) &&
-	     gdk_iswalnum (GTK_TEXT_INDEX(text, text->cursor_mark.index-1)))
-	decrement_mark (&text->cursor_mark);
+      CharClass cc = char_class (text, text->cursor_mark.index - 1);
+      if (cc == CHAR_CLASS_ALNUM || cc == CHAR_CLASS_IDEOGRAM)
+	break;
+      decrement_mark (&text->cursor_mark);
     }
-  else
+  while (text->cursor_mark.index > 0)
     {
-      while ((text->cursor_mark.index > 0) &&
-	     !isalnum (GTK_TEXT_INDEX(text, text->cursor_mark.index-1)))
-	decrement_mark (&text->cursor_mark);
-      
-      while ((text->cursor_mark.index > 0) &&
-	     isalnum (GTK_TEXT_INDEX(text, text->cursor_mark.index-1)))
-	decrement_mark (&text->cursor_mark);
+      CharClass cc = char_class (text, text->cursor_mark.index - 1);
+      if (cc != CHAR_CLASS_ALNUM && cc != CHAR_CLASS_IDEOGRAM)
+	break;
+      decrement_mark (&text->cursor_mark);
     }
   
   find_cursor (text, TRUE);
@@ -4782,27 +4781,8 @@
 		      GtkPropertyMark saved_mark = lp.end;
 		      guint saved_characters = lp.displayable_chars;
 		      
-		      lp.displayable_chars += 1;
-		      
-		      if (text->use_wchar)
-			{
-			  while (!gdk_iswspace (GTK_TEXT_INDEX (text, lp.end.index)) &&
-				 (lp.end.index > lp.start.index))
-			    {
-			      decrement_mark (&lp.end);
-			      lp.displayable_chars -= 1;
-			    }
-			}
-		      else
-			{
-			  while (!isspace(GTK_TEXT_INDEX (text, lp.end.index)) &&
-				 (lp.end.index > lp.start.index))
-			    {
-			      decrement_mark (&lp.end);
-			      lp.displayable_chars -= 1;
-			    }
-			}
-		      
+		      find_word_wrap_position (text, &lp);
+
 		      /* If whole line is one word, revert to char wrapping */
 		      if (lp.end.index == lp.start.index)
 			{
@@ -4848,6 +4828,54 @@
   lp.tab_cont_next = *next_cont;
   
   return lp;
+}
+
+static CharClass
+char_class (GtkText* text, guint index)
+{
+  GdkWChar wc;
+  wc = GTK_TEXT_INDEX (text, index);
+  if (text->use_wchar)
+    {
+      if (gdk_iswspace (wc))
+	return CHAR_CLASS_SPACE;
+      else if (gdk_iswalnum (wc))
+	return CHAR_CLASS_ALNUM;
+      else if (gdk_iswpunct (wc) || gdk_iswcntrl (wc))
+	return CHAR_CLASS_OTHERS;
+      else
+	return CHAR_CLASS_IDEOGRAM;
+    }
+  else
+    {
+      if (isspace (wc))
+	return CHAR_CLASS_SPACE;
+      else if (isalnum (wc))
+	return CHAR_CLASS_ALNUM;
+      else if (ispunct (wc) || iscntrl (wc))
+	return CHAR_CLASS_OTHERS;
+      else
+	return CHAR_CLASS_IDEOGRAM;
+    }
+}
+
+static void
+find_word_wrap_position (GtkText* text, LineParams *lp)
+{
+  while (lp->end.index > lp->start.index &&
+	 char_class (text, lp->end.index) != CHAR_CLASS_SPACE &&
+	 char_class (text, lp->end.index) != CHAR_CLASS_IDEOGRAM &&
+	 char_class (text, lp->end.index - 1) != CHAR_CLASS_IDEOGRAM)
+    {
+      decrement_mark (&lp->end);
+      lp->displayable_chars -= 1;
+    }
+
+  /* lp->end.index points the position to be cut just now. If it's not a
+   * space, move it to the next display line. */
+  if (lp->end.index > lp->start.index &&
+      char_class (text, lp->end.index) != CHAR_CLASS_SPACE)
+    decrement_mark (&lp->end);
 }
 
 static void
diff -ruN gtk+-1.2.10/gtk/gtktext.c.orig gtk-n/gtk/gtktext.c.orig
--- gtk+-1.2.10/gtk/gtktext.c.orig	Thu Jan  1 01:00:00 1970
+++ gtk-n/gtk/gtktext.c.orig	Thu Mar 15 21:15:12 2001
@@ -0,0 +1,5684 @@
+/* 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 Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-1999.  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/. 
+ */
+
+#include <ctype.h>
+#include <string.h>
+#include "gdk/gdkkeysyms.h"
+#include "gdk/gdki18n.h"
+#include "gtkmain.h"
+#include "gtkselection.h"
+#include "gtksignal.h"
+#include "gtktext.h"
+#include "line-wrap.xbm"
+#include "line-arrow.xbm"
+
+
+#define INITIAL_BUFFER_SIZE      1024
+#define INITIAL_LINE_CACHE_SIZE  256
+#define MIN_GAP_SIZE             256
+#define LINE_DELIM               '\n'
+#define MIN_TEXT_WIDTH_LINES     20
+#define MIN_TEXT_HEIGHT_LINES    10
+#define TEXT_BORDER_ROOM         1
+#define LINE_WRAP_ROOM           8           /* The bitmaps are 6 wide. */
+#define DEFAULT_TAB_STOP_WIDTH   4
+#define SCROLL_PIXELS            5
+#define KEY_SCROLL_PIXELS        10
+#define SCROLL_TIME              100
+#define FREEZE_LENGTH            1024        
+/* Freeze text when inserting or deleting more than this many characters */
+
+#define SET_PROPERTY_MARK(m, p, o)  do {                   \
+                                      (m)->property = (p); \
+			              (m)->offset = (o);   \
+			            } while (0)
+#define MARK_CURRENT_PROPERTY(mark) ((TextProperty*)(mark)->property->data)
+#define MARK_NEXT_PROPERTY(mark)    ((TextProperty*)(mark)->property->next->data)
+#define MARK_PREV_PROPERTY(mark)    ((TextProperty*)((mark)->property->prev ?     \
+						     (mark)->property->prev->data \
+						     : NULL))
+#define MARK_PREV_LIST_PTR(mark)    ((mark)->property->prev)
+#define MARK_LIST_PTR(mark)         ((mark)->property)
+#define MARK_NEXT_LIST_PTR(mark)    ((mark)->property->next)
+#define MARK_OFFSET(mark)           ((mark)->offset)
+#define MARK_PROPERTY_LENGTH(mark)  (MARK_CURRENT_PROPERTY(mark)->length)
+
+
+#define MARK_CURRENT_FONT(text, mark) \
+  ((MARK_CURRENT_PROPERTY(mark)->flags & PROPERTY_FONT) ? \
+         MARK_CURRENT_PROPERTY(mark)->font->gdk_font : \
+         GTK_WIDGET (text)->style->font)
+#define MARK_CURRENT_FORE(text, mark) \
+  ((MARK_CURRENT_PROPERTY(mark)->flags & PROPERTY_FOREGROUND) ? \
+         &MARK_CURRENT_PROPERTY(mark)->fore_color : \
+         &((GtkWidget *)text)->style->text[((GtkWidget *)text)->state])
+#define MARK_CURRENT_BACK(text, mark) \
+  ((MARK_CURRENT_PROPERTY(mark)->flags & PROPERTY_BACKGROUND) ? \
+         &MARK_CURRENT_PROPERTY(mark)->back_color : \
+         &((GtkWidget *)text)->style->base[((GtkWidget *)text)->state])
+#define MARK_CURRENT_TEXT_FONT(text, mark) \
+  ((MARK_CURRENT_PROPERTY(mark)->flags & PROPERTY_FONT) ? \
+         MARK_CURRENT_PROPERTY(mark)->font : \
+         text->current_font)
+
+#define TEXT_LENGTH(t)              ((t)->text_end - (t)->gap_size)
+#define FONT_HEIGHT(f)              ((f)->ascent + (f)->descent)
+#define LINE_HEIGHT(l)              ((l).font_ascent + (l).font_descent)
+#define LINE_CONTAINS(l, i)         ((l).start.index <= (i) && (l).end.index >= (i))
+#define LINE_STARTS_AT(l, i)        ((l).start.index == (i))
+#define LINE_START_PIXEL(l)         ((l).tab_cont.pixel_offset)
+#define LAST_INDEX(t, m)            ((m).index == TEXT_LENGTH(t))
+#define CACHE_DATA(c)               (*(LineParams*)(c)->data)
+
+enum {
+  ARG_0,
+  ARG_HADJUSTMENT,
+  ARG_VADJUSTMENT,
+  ARG_LINE_WRAP,
+  ARG_WORD_WRAP
+};
+
+typedef struct _TextProperty          TextProperty;
+typedef struct _TabStopMark           TabStopMark;
+typedef struct _PrevTabCont           PrevTabCont;
+typedef struct _FetchLinesData        FetchLinesData;
+typedef struct _LineParams            LineParams;
+typedef struct _SetVerticalScrollData SetVerticalScrollData;
+
+typedef gint (*LineIteratorFunction) (GtkText* text, LineParams* lp, void* data);
+
+typedef enum
+{
+  FetchLinesPixels,
+  FetchLinesCount
+} FLType;
+
+struct _SetVerticalScrollData {
+  gint pixel_height;
+  gint last_didnt_wrap;
+  gint last_line_start;
+  GtkPropertyMark mark;
+};
+
+struct _GtkTextFont
+{
+  /* The actual font. */
+  GdkFont *gdk_font;
+  guint ref_count;
+
+  gint16 char_widths[256];
+};
+
+typedef enum {
+  PROPERTY_FONT =       1 << 0,
+  PROPERTY_FOREGROUND = 1 << 1,
+  PROPERTY_BACKGROUND = 1 << 2
+} TextPropertyFlags;
+
+struct _TextProperty
+{
+  /* Font. */
+  GtkTextFont* font;
+
+  /* Background Color. */
+  GdkColor back_color;
+  
+  /* Foreground Color. */
+  GdkColor fore_color;
+
+  /* Show which properties are set */
+  TextPropertyFlags flags;
+
+  /* Length of this property. */
+  guint length;
+};
+
+struct _TabStopMark
+{
+  GList* tab_stops; /* Index into list containing the next tab position.  If
+		     * NULL, using default widths. */
+  gint to_next_tab;
+};
+
+struct _PrevTabCont
+{
+  guint pixel_offset;
+  TabStopMark tab_start;
+};
+
+struct _FetchLinesData
+{
+  GList* new_lines;
+  FLType fl_type;
+  gint data;
+  gint data_max;
+};
+
+struct _LineParams
+{
+  guint font_ascent;
+  guint font_descent;
+  guint pixel_width;
+  guint displayable_chars;
+  guint wraps : 1;
+  
+  PrevTabCont tab_cont;
+  PrevTabCont tab_cont_next;
+  
+  GtkPropertyMark start;
+  GtkPropertyMark end;
+};
+
+
+static void  gtk_text_class_init     (GtkTextClass   *klass);
+static void  gtk_text_set_arg        (GtkObject      *object,
+				      GtkArg         *arg,
+				      guint           arg_id);
+static void  gtk_text_get_arg        (GtkObject      *object,
+				      GtkArg         *arg,
+				      guint           arg_id);
+static void  gtk_text_init           (GtkText        *text);
+static void  gtk_text_destroy        (GtkObject      *object);
+static void  gtk_text_finalize       (GtkObject      *object);
+static void  gtk_text_realize        (GtkWidget      *widget);
+static void  gtk_text_unrealize      (GtkWidget      *widget);
+static void  gtk_text_style_set	     (GtkWidget      *widget,
+				      GtkStyle       *previous_style);
+static void  gtk_text_state_changed  (GtkWidget      *widget,
+				      GtkStateType    previous_state);
+static void  gtk_text_draw_focus     (GtkWidget      *widget);
+static void  gtk_text_size_request   (GtkWidget      *widget,
+				      GtkRequisition *requisition);
+static void  gtk_text_size_allocate  (GtkWidget      *widget,
+				      GtkAllocation  *allocation);
+static void  gtk_text_adjustment     (GtkAdjustment  *adjustment,
+				      GtkText        *text);
+static void  gtk_text_disconnect     (GtkAdjustment  *adjustment,
+				      GtkText        *text);
+
+static void gtk_text_insert_text       (GtkEditable       *editable,
+					const gchar       *new_text,
+					gint               new_text_length,
+					gint               *position);
+static void gtk_text_delete_text       (GtkEditable        *editable,
+					gint               start_pos,
+					gint               end_pos);
+static void gtk_text_update_text       (GtkEditable       *editable,
+					gint               start_pos,
+					gint               end_pos);
+static gchar *gtk_text_get_chars       (GtkEditable       *editable,
+					gint               start,
+					gint               end);
+static void gtk_text_set_selection     (GtkEditable       *editable,
+					gint               start,
+					gint               end);
+static void gtk_text_real_set_editable (GtkEditable       *editable,
+					gboolean           is_editable);
+
+/* Event handlers */
+static void  gtk_text_draw              (GtkWidget         *widget,
+					 GdkRectangle      *area);
+static gint  gtk_text_expose            (GtkWidget         *widget,
+					 GdkEventExpose    *event);
+static gint  gtk_text_button_press      (GtkWidget         *widget,
+					 GdkEventButton    *event);
+static gint  gtk_text_button_release    (GtkWidget         *widget,
+					 GdkEventButton    *event);
+static gint  gtk_text_motion_notify     (GtkWidget         *widget,
+					 GdkEventMotion    *event);
+static gint  gtk_text_key_press         (GtkWidget         *widget,
+					 GdkEventKey       *event);
+static gint  gtk_text_focus_in          (GtkWidget         *widget,
+					 GdkEventFocus     *event);
+static gint  gtk_text_focus_out         (GtkWidget         *widget,
+				         GdkEventFocus     *event);
+
+static void move_gap (GtkText* text, guint index);
+static void make_forward_space (GtkText* text, guint len);
+
+/* Property management */
+static GtkTextFont* get_text_font (GdkFont* gfont);
+static void         text_font_unref (GtkTextFont *text_font);
+
+static void insert_text_property (GtkText* text, GdkFont* font,
+				  GdkColor *fore, GdkColor* back, guint len);
+static TextProperty* new_text_property (GtkText *text, GdkFont* font, 
+					GdkColor* fore, GdkColor* back, guint length);
+static void destroy_text_property (TextProperty *prop);
+static void init_properties      (GtkText *text);
+static void realize_property     (GtkText *text, TextProperty *prop);
+static void realize_properties   (GtkText *text);
+static void unrealize_property   (GtkText *text, TextProperty *prop);
+static void unrealize_properties (GtkText *text);
+
+static void delete_text_property (GtkText* text, guint len);
+
+static guint pixel_height_of (GtkText* text, GList* cache_line);
+
+/* Property Movement and Size Computations */
+static void advance_mark (GtkPropertyMark* mark);
+static void decrement_mark (GtkPropertyMark* mark);
+static void advance_mark_n (GtkPropertyMark* mark, gint n);
+static void decrement_mark_n (GtkPropertyMark* mark, gint n);
+static void move_mark_n (GtkPropertyMark* mark, gint n);
+static GtkPropertyMark find_mark (GtkText* text, guint mark_position);
+static GtkPropertyMark find_mark_near (GtkText* text, guint mark_position, const GtkPropertyMark* near);
+static void find_line_containing_point (GtkText* text, guint point,
+					gboolean scroll);
+
+/* Display */
+static void compute_lines_pixels (GtkText* text, guint char_count,
+				  guint *lines, guint *pixels);
+
+static gint total_line_height (GtkText* text,
+			       GList* line,
+			       gint line_count);
+static LineParams find_line_params (GtkText* text,
+				    const GtkPropertyMark *mark,
+				    const PrevTabCont *tab_cont,
+				    PrevTabCont *next_cont);
+static void recompute_geometry (GtkText* text);
+static void insert_expose (GtkText* text, guint old_pixels, gint nchars, guint new_line_count);
+static void delete_expose (GtkText* text,
+			   guint nchars,
+			   guint old_lines, 
+			   guint old_pixels);
+static GdkGC *create_bg_gc (GtkText *text);
+static void clear_area (GtkText *text, GdkRectangle *area);
+static void draw_line (GtkText* text,
+		       gint pixel_height,
+		       LineParams* lp);
+static void draw_line_wrap (GtkText* text,
+			    guint height);
+static void draw_cursor (GtkText* text, gint absolute);
+static void undraw_cursor (GtkText* text, gint absolute);
+static gint drawn_cursor_min (GtkText* text);
+static gint drawn_cursor_max (GtkText* text);
+static void expose_text (GtkText* text, GdkRectangle *area, gboolean cursor);
+
+/* Search and Placement. */
+static void find_cursor (GtkText* text,
+			 gboolean scroll);
+static void find_cursor_at_line (GtkText* text,
+				 const LineParams* start_line,
+				 gint pixel_height);
+static void find_mouse_cursor (GtkText* text, gint x, gint y);
+
+/* Scrolling. */
+static void adjust_adj  (GtkText* text, GtkAdjustment* adj);
+static void scroll_up   (GtkText* text, gint diff);
+static void scroll_down (GtkText* text, gint diff);
+static void scroll_int  (GtkText* text, gint diff);
+
+static void process_exposes (GtkText *text);
+
+/* Cache Management. */
+static void   free_cache        (GtkText* text);
+static GList* remove_cache_line (GtkText* text, GList* list);
+
+/* Key Motion. */
+static void move_cursor_buffer_ver (GtkText *text, int dir);
+static void move_cursor_page_ver (GtkText *text, int dir);
+static void move_cursor_ver (GtkText *text, int count);
+static void move_cursor_hor (GtkText *text, int count);
+
+/* Binding actions */
+static void gtk_text_move_cursor         (GtkEditable *editable,
+					  gint         x,
+					  gint         y);
+static void gtk_text_move_word           (GtkEditable *editable,
+					  gint         n);
+static void gtk_text_move_page           (GtkEditable *editable,
+					  gint         x,
+					  gint         y);
+static void gtk_text_move_to_row         (GtkEditable *editable,
+					  gint         row);
+static void gtk_text_move_to_column      (GtkEditable *editable,
+					  gint         row);
+static void gtk_text_kill_char           (GtkEditable *editable,
+					  gint         direction);
+static void gtk_text_kill_word           (GtkEditable *editable,
+					  gint         direction);
+static void gtk_text_kill_line           (GtkEditable *editable,
+					  gint         direction);
+
+/* To be removed */
+static void gtk_text_move_forward_character    (GtkText          *text);
+static void gtk_text_move_backward_character   (GtkText          *text);
+static void gtk_text_move_forward_word         (GtkText          *text);
+static void gtk_text_move_backward_word        (GtkText          *text);
+static void gtk_text_move_beginning_of_line    (GtkText          *text);
+static void gtk_text_move_end_of_line          (GtkText          *text);
+static void gtk_text_move_next_line            (GtkText          *text);
+static void gtk_text_move_previous_line        (GtkText          *text);
+
+static void gtk_text_delete_forward_character  (GtkText          *text);
+static void gtk_text_delete_backward_character (GtkText          *text);
+static void gtk_text_delete_forward_word       (GtkText          *text);
+static void gtk_text_delete_backward_word      (GtkText          *text);
+static void gtk_text_delete_line               (GtkText          *text);
+static void gtk_text_delete_to_line_end        (GtkText          *text);
+static void gtk_text_select_word               (GtkText          *text,
+						guint32           time);
+static void gtk_text_select_line               (GtkText          *text,
+						guint32           time);
+
+static void gtk_text_set_position  (GtkEditable       *editable,
+				    gint               position);
+
+/* #define DEBUG_GTK_TEXT */
+
+#if defined(DEBUG_GTK_TEXT) && defined(__GNUC__)
+/* Debugging utilities. */
+static void gtk_text_assert_mark (GtkText         *text,
+				  GtkPropertyMark *mark,
+				  GtkPropertyMark *before,
+				  GtkPropertyMark *after,
+				  const gchar     *msg,
+				  const gchar     *where,
+				  gint             line);
+
+static void gtk_text_assert (GtkText         *text,
+			     const gchar     *msg,
+			     gint             line);
+static void gtk_text_show_cache_line (GtkText *text, GList *cache,
+				      const char* what, const char* func, gint line);
+static void gtk_text_show_cache (GtkText *text, const char* func, gint line);
+static void gtk_text_show_adj (GtkText *text,
+			       GtkAdjustment *adj,
+			       const char* what,
+			       const char* func,
+			       gint line);
+static void gtk_text_show_props (GtkText* test,
+				 const char* func,
+				 int line);
+
+#define TDEBUG(args) g_message args
+#define TEXT_ASSERT(text) gtk_text_assert (text,__PRETTY_FUNCTION__,__LINE__)
+#define TEXT_ASSERT_MARK(text,mark,msg) gtk_text_assert_mark (text,mark, \
+					   __PRETTY_FUNCTION__,msg,__LINE__)
+#define TEXT_SHOW(text) gtk_text_show_cache (text, __PRETTY_FUNCTION__,__LINE__)
+#define TEXT_SHOW_LINE(text,line,msg) gtk_text_show_cache_line (text,line,msg,\
+					   __PRETTY_FUNCTION__,__LINE__)
+#define TEXT_SHOW_ADJ(text,adj,msg) gtk_text_show_adj (text,adj,msg, \
+					  __PRETTY_FUNCTION__,__LINE__)
+#else
+#define TDEBUG(args)
+#define TEXT_ASSERT(text)
+#define TEXT_ASSERT_MARK(text,mark,msg)
+#define TEXT_SHOW(text)
+#define TEXT_SHOW_LINE(text,line,msg)
+#define TEXT_SHOW_ADJ(text,adj,msg)
+#endif
+
+/* Memory Management. */
+static GMemChunk  *params_mem_chunk    = NULL;
+static GMemChunk  *text_property_chunk = NULL;
+
+static GtkWidgetClass *parent_class = NULL;
+
+
+static const GtkTextFunction control_keys[26] =
+{
+  (GtkTextFunction)gtk_text_move_beginning_of_line,    /* a */
+  (GtkTextFunction)gtk_text_move_backward_character,   /* b */
+  (GtkTextFunction)gtk_editable_copy_clipboard,        /* c */
+  (GtkTextFunction)gtk_text_delete_forward_character,  /* d */
+  (GtkTextFunction)gtk_text_move_end_of_line,          /* e */
+  (GtkTextFunction)gtk_text_move_forward_character,    /* f */
+  NULL,                                                /* g */
+  (GtkTextFunction)gtk_text_delete_backward_character, /* h */
+  NULL,                                                /* i */
+  NULL,                                                /* j */
+  (GtkTextFunction)gtk_text_delete_to_line_end,        /* k */
+  NULL,                                                /* l */
+  NULL,                                                /* m */
+  (GtkTextFunction)gtk_text_move_next_line,            /* n */
+  NULL,                                                /* o */
+  (GtkTextFunction)gtk_text_move_previous_line,        /* p */
+  NULL,                                                /* q */
+  NULL,                                                /* r */
+  NULL,                                                /* s */
+  NULL,                                                /* t */
+  (GtkTextFunction)gtk_text_delete_line,               /* u */
+  (GtkTextFunction)gtk_editable_paste_clipboard,       /* v */
+  (GtkTextFunction)gtk_text_delete_backward_word,      /* w */
+  (GtkTextFunction)gtk_editable_cut_clipboard,         /* x */
+  NULL,                                                /* y */
+  NULL,                                                /* z */
+};
+
+static const GtkTextFunction alt_keys[26] =
+{
+  NULL,                                                /* a */
+  (GtkTextFunction)gtk_text_move_backward_word,        /* b */
+  NULL,                                                /* c */
+  (GtkTextFunction)gtk_text_delete_forward_word,       /* d */
+  NULL,                                           /* e */
+  (GtkTextFunction)gtk_text_move_forward_word,         /* f */
+  NULL,                                           /* g */
+  NULL,                                           /* h */
+  NULL,                                           /* i */
+  NULL,                                           /* j */
+  NULL,                                           /* k */
+  NULL,                                           /* l */
+  NULL,                                           /* m */
+  NULL,                                           /* n */
+  NULL,                                           /* o */
+  NULL,                                           /* p */
+  NULL,                                           /* q */
+  NULL,                                           /* r */
+  NULL,                                           /* s */
+  NULL,                                           /* t */
+  NULL,                                           /* u */
+  NULL,                                           /* v */
+  NULL,                                           /* w */
+  NULL,                                           /* x */
+  NULL,                                           /* y */
+  NULL,                                           /* z */
+};
+
+
+/**********************************************************************/
+/*			        Widget Crap                           */
+/**********************************************************************/
+
+GtkType
+gtk_text_get_type (void)
+{
+  static GtkType text_type = 0;
+  
+  if (!text_type)
+    {
+      static const GtkTypeInfo text_info =
+      {
+	"GtkText",
+	sizeof (GtkText),
+	sizeof (GtkTextClass),
+	(GtkClassInitFunc) gtk_text_class_init,
+	(GtkObjectInitFunc) gtk_text_init,
+	/* reserved_1 */ NULL,
+        /* reserved_2 */ NULL,
+        (GtkClassInitFunc) NULL,
+      };
+      
+      text_type = gtk_type_unique (GTK_TYPE_EDITABLE, &text_info);
+    }
+  
+  return text_type;
+}
+
+static void
+gtk_text_class_init (GtkTextClass *class)
+{
+  GtkObjectClass *object_class;
+  GtkWidgetClass *widget_class;
+  GtkEditableClass *editable_class;
+  
+  object_class = (GtkObjectClass*) class;
+  widget_class = (GtkWidgetClass*) class;
+  editable_class = (GtkEditableClass*) class;
+  parent_class = gtk_type_class (GTK_TYPE_EDITABLE);
+
+  gtk_object_add_arg_type ("GtkText::hadjustment",
+			   GTK_TYPE_ADJUSTMENT,
+			   GTK_ARG_READWRITE | GTK_ARG_CONSTRUCT,
+			   ARG_HADJUSTMENT);
+  gtk_object_add_arg_type ("GtkText::vadjustment",
+			   GTK_TYPE_ADJUSTMENT,
+			   GTK_ARG_READWRITE | GTK_ARG_CONSTRUCT,
+			   ARG_VADJUSTMENT);
+  gtk_object_add_arg_type ("GtkText::line_wrap",
+			   GTK_TYPE_BOOL,
+			   GTK_ARG_READWRITE,
+			   ARG_LINE_WRAP);
+  gtk_object_add_arg_type ("GtkText::word_wrap",
+			   GTK_TYPE_BOOL,
+			   GTK_ARG_READWRITE,
+			   ARG_WORD_WRAP);
+
+  object_class->set_arg = gtk_text_set_arg;
+  object_class->get_arg = gtk_text_get_arg;
+  object_class->destroy = gtk_text_destroy;
+  object_class->finalize = gtk_text_finalize;
+  
+  widget_class->realize = gtk_text_realize;
+  widget_class->unrealize = gtk_text_unrealize;
+  widget_class->style_set = gtk_text_style_set;
+  widget_class->state_changed = gtk_text_state_changed;
+  widget_class->draw_focus = gtk_text_draw_focus;
+  widget_class->size_request = gtk_text_size_request;
+  widget_class->size_allocate = gtk_text_size_allocate;
+  widget_class->draw = gtk_text_draw;
+  widget_class->expose_event = gtk_text_expose;
+  widget_class->button_press_event = gtk_text_button_press;
+  widget_class->button_release_event = gtk_text_button_release;
+  widget_class->motion_notify_event = gtk_text_motion_notify;
+  widget_class->key_press_event = gtk_text_key_press;
+  widget_class->focus_in_event = gtk_text_focus_in;
+  widget_class->focus_out_event = gtk_text_focus_out;
+  
+  widget_class->set_scroll_adjustments_signal =
+    gtk_signal_new ("set_scroll_adjustments",
+		    GTK_RUN_LAST,
+		    object_class->type,
+		    GTK_SIGNAL_OFFSET (GtkTextClass, set_scroll_adjustments),
+		    gtk_marshal_NONE__POINTER_POINTER,
+		    GTK_TYPE_NONE, 2, GTK_TYPE_ADJUSTMENT, GTK_TYPE_ADJUSTMENT);
+
+  editable_class->set_editable = gtk_text_real_set_editable;
+  editable_class->insert_text = gtk_text_insert_text;
+  editable_class->delete_text = gtk_text_delete_text;
+  
+  editable_class->move_cursor = gtk_text_move_cursor;
+  editable_class->move_word = gtk_text_move_word;
+  editable_class->move_page = gtk_text_move_page;
+  editable_class->move_to_row = gtk_text_move_to_row;
+  editable_class->move_to_column = gtk_text_move_to_column;
+  
+  editable_class->kill_char = gtk_text_kill_char;
+  editable_class->kill_word = gtk_text_kill_word;
+  editable_class->kill_line = gtk_text_kill_line;
+  
+  editable_class->update_text = gtk_text_update_text;
+  editable_class->get_chars   = gtk_text_get_chars;
+  editable_class->set_selection = gtk_text_set_selection;
+  editable_class->set_position = gtk_text_set_position;
+
+  class->set_scroll_adjustments = gtk_text_set_adjustments;
+}
+
+static void
+gtk_text_set_arg (GtkObject        *object,
+		  GtkArg           *arg,
+		  guint             arg_id)
+{
+  GtkText *text;
+  
+  text = GTK_TEXT (object);
+  
+  switch (arg_id)
+    {
+    case ARG_HADJUSTMENT:
+      gtk_text_set_adjustments (text,
+				GTK_VALUE_POINTER (*arg),
+				text->vadj);
+      break;
+    case ARG_VADJUSTMENT:
+      gtk_text_set_adjustments (text,
+				text->hadj,
+				GTK_VALUE_POINTER (*arg));
+      break;
+    case ARG_LINE_WRAP:
+      gtk_text_set_line_wrap (text, GTK_VALUE_BOOL (*arg));
+      break;
+    case ARG_WORD_WRAP:
+      gtk_text_set_word_wrap (text, GTK_VALUE_BOOL (*arg));
+      break;
+    default:
+      break;
+    }
+}
+
+static void
+gtk_text_get_arg (GtkObject        *object,
+		  GtkArg           *arg,
+		  guint             arg_id)
+{
+  GtkText *text;
+  
+  text = GTK_TEXT (object);
+  
+  switch (arg_id)
+    {
+    case ARG_HADJUSTMENT:
+      GTK_VALUE_POINTER (*arg) = text->hadj;
+      break;
+    case ARG_VADJUSTMENT:
+      GTK_VALUE_POINTER (*arg) = text->vadj;
+      break;
+    case ARG_LINE_WRAP:
+      GTK_VALUE_BOOL (*arg) = text->line_wrap;
+      break;
+    case ARG_WORD_WRAP:
+      GTK_VALUE_BOOL (*arg) = text->word_wrap;
+      break;
+    default:
+      arg->type = GTK_TYPE_INVALID;
+      break;
+    }
+}
+
+static void
+gtk_text_init (GtkText *text)
+{
+  GTK_WIDGET_SET_FLAGS (text, GTK_CAN_FOCUS);
+
+  text->text_area = NULL;
+  text->hadj = NULL;
+  text->vadj = NULL;
+  text->gc = NULL;
+  text->bg_gc = NULL;
+  text->line_wrap_bitmap = NULL;
+  text->line_arrow_bitmap = NULL;
+  
+  text->use_wchar = FALSE;
+  text->text.ch = g_new (guchar, INITIAL_BUFFER_SIZE);
+  text->text_len = INITIAL_BUFFER_SIZE;
+ 
+  text->scratch_buffer.ch = NULL;
+  text->scratch_buffer_len = 0;
+ 
+  text->freeze_count = 0;
+  
+  if (!params_mem_chunk)
+    params_mem_chunk = g_mem_chunk_new ("LineParams",
+					sizeof (LineParams),
+					256 * sizeof (LineParams),
+					G_ALLOC_AND_FREE);
+  
+  text->default_tab_width = 4;
+  text->tab_stops = NULL;
+  
+  text->tab_stops = g_list_prepend (text->tab_stops, (void*)8);
+  text->tab_stops = g_list_prepend (text->tab_stops, (void*)8);
+  
+  text->line_start_cache = NULL;
+  text->first_cut_pixels = 0;
+  
+  text->line_wrap = TRUE;
+  text->word_wrap = FALSE;
+  
+  text->timer = 0;
+  text->button = 0;
+  
+  text->current_font = NULL;
+  
+  init_properties (text);
+  
+  GTK_EDITABLE (text)->editable = FALSE;
+  
+  gtk_editable_set_position (GTK_EDITABLE (text), 0);
+}
+
+GtkWidget*
+gtk_text_new (GtkAdjustment *hadj,
+	      GtkAdjustment *vadj)
+{
+  GtkWidget *text;
+
+  if (hadj)
+    g_return_val_if_fail (GTK_IS_ADJUSTMENT (hadj), NULL);
+  if (vadj)
+    g_return_val_if_fail (GTK_IS_ADJUSTMENT (vadj), NULL);
+
+  text = gtk_widget_new (GTK_TYPE_TEXT,
+			 "hadjustment", hadj,
+			 "vadjustment", vadj,
+			 NULL);
+
+  return text;
+}
+
+void
+gtk_text_set_word_wrap (GtkText *text,
+			gint     word_wrap)
+{
+  g_return_if_fail (text != NULL);
+  g_return_if_fail (GTK_IS_TEXT (text));
+  
+  text->word_wrap = (word_wrap != FALSE);
+  
+  if (GTK_WIDGET_REALIZED (text))
+    {
+      recompute_geometry (text);
+      gtk_widget_queue_draw (GTK_WIDGET (text));
+    }
+}
+
+void
+gtk_text_set_line_wrap (GtkText *text,
+			gint     line_wrap)
+{
+  g_return_if_fail (text != NULL);
+  g_return_if_fail (GTK_IS_TEXT (text));
+  
+  text->line_wrap = (line_wrap != FALSE);
+  
+  if (GTK_WIDGET_REALIZED (text))
+    {
+      recompute_geometry (text);
+      gtk_widget_queue_draw (GTK_WIDGET (text));
+    }
+}
+
+void
+gtk_text_set_editable (GtkText *text,
+		       gboolean is_editable)
+{
+  g_return_if_fail (text != NULL);
+  g_return_if_fail (GTK_IS_TEXT (text));
+  
+  gtk_editable_set_editable (GTK_EDITABLE (text), is_editable);
+}
+
+static void
+gtk_text_real_set_editable (GtkEditable *editable,
+			    gboolean     is_editable)
+{
+  GtkText *text;
+  
+  g_return_if_fail (editable != NULL);
+  g_return_if_fail (GTK_IS_TEXT (editable));
+  
+  text = GTK_TEXT (editable);
+
+  editable->editable = (is_editable != FALSE);
+  
+  if (GTK_WIDGET_REALIZED (text))
+    {
+      recompute_geometry (text);
+      gtk_widget_queue_draw (GTK_WIDGET (text));
+    }
+}
+
+void
+gtk_text_set_adjustments (GtkText       *text,
+			  GtkAdjustment *hadj,
+			  GtkAdjustment *vadj)
+{
+  g_return_if_fail (text != NULL);
+  g_return_if_fail (GTK_IS_TEXT (text));
+  if (hadj)
+    g_return_if_fail (GTK_IS_ADJUSTMENT (hadj));
+  else
+    hadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
+  if (vadj)
+    g_return_if_fail (GTK_IS_ADJUSTMENT (vadj));
+  else
+    vadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
+  
+  if (text->hadj && (text->hadj != hadj))
+    {
+      gtk_signal_disconnect_by_data (GTK_OBJECT (text->hadj), text);
+      gtk_object_unref (GTK_OBJECT (text->hadj));
+    }
+  
+  if (text->vadj && (text->vadj != vadj))
+    {
+      gtk_signal_disconnect_by_data (GTK_OBJECT (text->vadj), text);
+      gtk_object_unref (GTK_OBJECT (text->vadj));
+    }
+  
+  if (text->hadj != hadj)
+    {
+      text->hadj = hadj;
+      gtk_object_ref (GTK_OBJECT (text->hadj));
+      gtk_object_sink (GTK_OBJECT (text->hadj));
+      
+      gtk_signal_connect (GTK_OBJECT (text->hadj), "changed",
+			  (GtkSignalFunc) gtk_text_adjustment,
+			  text);
+      gtk_signal_connect (GTK_OBJECT (text->hadj), "value_changed",
+			  (GtkSignalFunc) gtk_text_adjustment,
+			  text);
+      gtk_signal_connect (GTK_OBJECT (text->hadj), "disconnect",
+			  (GtkSignalFunc) gtk_text_disconnect,
+			  text);
+      gtk_text_adjustment (hadj, text);
+    }
+  
+  if (text->vadj != vadj)
+    {
+      text->vadj = vadj;
+      gtk_object_ref (GTK_OBJECT (text->vadj));
+      gtk_object_sink (GTK_OBJECT (text->vadj));
+      
+      gtk_signal_connect (GTK_OBJECT (text->vadj), "changed",
+			  (GtkSignalFunc) gtk_text_adjustment,
+			  text);
+      gtk_signal_connect (GTK_OBJECT (text->vadj), "value_changed",
+			  (GtkSignalFunc) gtk_text_adjustment,
+			  text);
+      gtk_signal_connect (GTK_OBJECT (text->vadj), "disconnect",
+			  (GtkSignalFunc) gtk_text_disconnect,
+			  text);
+      gtk_text_adjustment (vadj, text);
+    }
+}
+
+void
+gtk_text_set_point (GtkText *text,
+		    guint    index)
+{
+  g_return_if_fail (text != NULL);
+  g_return_if_fail (GTK_IS_TEXT (text));
+  g_return_if_fail (index <= TEXT_LENGTH (text));
+  
+  text->point = find_mark (text, index);
+}
+
+guint
+gtk_text_get_point (GtkText *text)
+{
+  g_return_val_if_fail (text != NULL, 0);
+  g_return_val_if_fail (GTK_IS_TEXT (text), 0);
+  
+  return text->point.index;
+}
+
+guint
+gtk_text_get_length (GtkText *text)
+{
+  g_return_val_if_fail (text != NULL, 0);
+  g_return_val_if_fail (GTK_IS_TEXT (text), 0);
+  
+  return TEXT_LENGTH (text);
+}
+
+void
+gtk_text_freeze (GtkText *text)
+{
+  g_return_if_fail (text != NULL);
+  g_return_if_fail (GTK_IS_TEXT (text));
+
+  text->freeze_count++;
+  undraw_cursor (text, FALSE);
+}
+
+void
+gtk_text_thaw (GtkText *text)
+{
+  g_return_if_fail (text != NULL);
+  g_return_if_fail (GTK_IS_TEXT (text));
+  
+  if (text->freeze_count)
+    if (!(--text->freeze_count) && GTK_WIDGET_REALIZED (text))
+      {
+	recompute_geometry (text);
+	gtk_widget_queue_draw (GTK_WIDGET (text));
+      }
+  draw_cursor (text, FALSE);
+}
+
+void
+gtk_text_insert (GtkText    *text,
+		 GdkFont    *font,
+		 GdkColor   *fore,
+		 GdkColor   *back,
+		 const char *chars,
+		 gint        nchars)
+{
+  GtkEditable *editable = GTK_EDITABLE (text);
+  gboolean frozen = FALSE;
+  
+  gint new_line_count = 1;
+  guint old_height = 0;
+  guint length;
+  guint i;
+  gint numwcs;
+  
+  g_return_if_fail (text != NULL);
+  g_return_if_fail (GTK_IS_TEXT (text));
+  if (nchars > 0)
+    g_return_if_fail (chars != NULL);
+  else
+    {
+      if (!nchars || !chars)
+	return;
+      nchars = strlen (chars);
+    }
+  length = nchars;
+  
+  if (!text->freeze_count && (length > FREEZE_LENGTH))
+    {
+      gtk_text_freeze (text);
+      frozen = TRUE;
+    }
+  
+  if (!text->freeze_count && (text->line_start_cache != NULL))
+    {
+      find_line_containing_point (text, text->point.index, TRUE);
+      old_height = total_line_height (text, text->current_line, 1);
+    }
+  
+  if ((TEXT_LENGTH (text) == 0) && (text->use_wchar == FALSE))
+    {
+      GtkWidget *widget;
+      widget = GTK_WIDGET (text);
+      gtk_widget_ensure_style (widget);
+      if ((widget->style) && (widget->style->font->type == GDK_FONT_FONTSET))
+ 	{
+ 	  text->use_wchar = TRUE;
+ 	  g_free (text->text.ch);
+ 	  text->text.wc = g_new (GdkWChar, INITIAL_BUFFER_SIZE);
+ 	  text->text_len = INITIAL_BUFFER_SIZE;
+ 	  if (text->scratch_buffer.ch)
+ 	    g_free (text->scratch_buffer.ch);
+ 	  text->scratch_buffer.wc = NULL;
+ 	  text->scratch_buffer_len = 0;
+ 	}
+    }
+ 
+  move_gap (text, text->point.index);
+  make_forward_space (text, length);
+ 
+  if (text->use_wchar)
+    {
+      char *chars_nt = (char *)chars;
+      if (nchars > 0)
+	{
+	  chars_nt = g_new (char, length+1);
+	  memcpy (chars_nt, chars, length);
+	  chars_nt[length] = 0;
+	}
+      numwcs = gdk_mbstowcs (text->text.wc + text->gap_position, chars_nt,
+ 			     length);
+      if (chars_nt != chars)
+	g_free(chars_nt);
+      if (numwcs < 0)
+	numwcs = 0;
+    }
+  else
+    {
+      numwcs = length;
+      memcpy(text->text.ch + text->gap_position, chars, length);
+    }
+ 
+  if (!text->freeze_count && (text->line_start_cache != NULL))
+    {
+      if (text->use_wchar)
+ 	{
+ 	  for (i=0; i<numwcs; i++)
+ 	    if (text->text.wc[text->gap_position + i] == '\n')
+ 	      new_line_count++;
+	}
+      else
+ 	{
+ 	  for (i=0; i<numwcs; i++)
+ 	    if (text->text.ch[text->gap_position + i] == '\n')
+ 	      new_line_count++;
+ 	}
+    }
+ 
+  if (numwcs > 0)
+    {
+      insert_text_property (text, font, fore, back, numwcs);
+   
+      text->gap_size -= numwcs;
+      text->gap_position += numwcs;
+   
+      if (text->point.index < text->first_line_start_index)
+ 	text->first_line_start_index += numwcs;
+      if (text->point.index < editable->selection_start_pos)
+ 	editable->selection_start_pos += numwcs;
+      if (text->point.index < editable->selection_end_pos)
+ 	editable->selection_end_pos += numwcs;
+      /* We'll reset the cursor later anyways if we aren't frozen */
+      if (text->point.index < text->cursor_mark.index)
+ 	text->cursor_mark.index += numwcs;
+  
+      advance_mark_n (&text->point, numwcs);
+  
+      if (!text->freeze_count && (text->line_start_cache != NULL))
+	insert_expose (text, old_height, numwcs, new_line_count);
+    }
+
+  if (frozen)
+    gtk_text_thaw (text);
+}
+
+gint
+gtk_text_backward_delete (GtkText *text,
+			  guint    nchars)
+{
+  g_return_val_if_fail (text != NULL, 0);
+  g_return_val_if_fail (GTK_IS_TEXT (text), 0);
+  
+  if (nchars > text->point.index || nchars <= 0)
+    return FALSE;
+  
+  gtk_text_set_point (text, text->point.index - nchars);
+  
+  return gtk_text_forward_delete (text, nchars);
+}
+
+gint
+gtk_text_forward_delete (GtkText *text,
+			 guint    nchars)
+{
+  guint old_lines, old_height;
+  GtkEditable *editable = GTK_EDITABLE (text);
+  gboolean frozen = FALSE;
+  
+  g_return_val_if_fail (text != NULL, 0);
+  g_return_val_if_fail (GTK_IS_TEXT (text), 0);
+  
+  if (text->point.index + nchars > TEXT_LENGTH (text) || nchars <= 0)
+    return FALSE;
+  
+  if (!text->freeze_count && nchars > FREEZE_LENGTH)
+    {
+      gtk_text_freeze (text);
+      frozen = TRUE;
+    }
+  
+  if (!text->freeze_count && text->line_start_cache != NULL)
+    {
+      /* We need to undraw the cursor here, since we may later
+       * delete the cursor's property
+       */
+      undraw_cursor (text, FALSE);
+      find_line_containing_point (text, text->point.index, TRUE);
+      compute_lines_pixels (text, nchars, &old_lines, &old_height);
+    }
+  
+  /* FIXME, or resizing after deleting will be odd */
+  if (text->point.index < text->first_line_start_index)
+    {
+      if (text->point.index + nchars >= text->first_line_start_index)
+	{
+	  text->first_line_start_index = text->point.index;
+	  while ((text->first_line_start_index > 0) &&
+		 (GTK_TEXT_INDEX (text, text->first_line_start_index - 1)
+		  != LINE_DELIM))
+	    text->first_line_start_index -= 1;
+	  
+	}
+      else
+	text->first_line_start_index -= nchars;
+    }
+  
+  if (text->point.index < editable->selection_start_pos)
+    editable->selection_start_pos -= 
+      MIN(nchars, editable->selection_start_pos - text->point.index);
+  if (text->point.index < editable->selection_end_pos)
+    editable->selection_end_pos -= 
+      MIN(nchars, editable->selection_end_pos - text->point.index);
+  /* We'll reset the cursor later anyways if we aren't frozen */
+  if (text->point.index < text->cursor_mark.index)
+    move_mark_n (&text->cursor_mark, 
+		 -MIN(nchars, text->cursor_mark.index - text->point.index));
+  
+  move_gap (text, text->point.index);
+  
+  text->gap_size += nchars;
+  
+  delete_text_property (text, nchars);
+  
+  if (!text->freeze_count && (text->line_start_cache != NULL))
+    {
+      delete_expose (text, nchars, old_lines, old_height);
+      draw_cursor (text, FALSE);
+    }
+  
+  if (frozen)
+    gtk_text_thaw (text);
+  
+  return TRUE;
+}
+
+static void
+gtk_text_set_position (GtkEditable *editable,
+		       gint position)
+{
+  GtkText *text = (GtkText *) editable;
+  
+  undraw_cursor (text, FALSE);
+  text->cursor_mark = find_mark (text, position);
+  find_cursor (text, TRUE);
+  draw_cursor (text, FALSE);
+  gtk_editable_select_region (editable, 0, 0);
+}
+
+static gchar *    
+gtk_text_get_chars (GtkEditable   *editable,
+		    gint           start_pos,
+		    gint           end_pos)
+{
+  GtkText *text;
+
+  gchar *retval;
+  
+  g_return_val_if_fail (editable != NULL, NULL);
+  g_return_val_if_fail (GTK_IS_TEXT (editable), NULL);
+  text = GTK_TEXT (editable);
+  
+  if (end_pos < 0)
+    end_pos = TEXT_LENGTH (text);
+  
+  if ((start_pos < 0) || 
+      (end_pos > TEXT_LENGTH (text)) || 
+      (end_pos < start_pos))
+    return NULL;
+  
+  move_gap (text, TEXT_LENGTH (text));
+  make_forward_space (text, 1);
+
+  if (text->use_wchar)
+    {
+      GdkWChar ch;
+      ch = text->text.wc[end_pos];
+      text->text.wc[end_pos] = 0;
+      retval = gdk_wcstombs (text->text.wc + start_pos);
+      text->text.wc[end_pos] = ch;
+    }
+  else
+    {
+      guchar ch;
+      ch = text->text.ch[end_pos];
+      text->text.ch[end_pos] = 0;
+      retval = g_strdup (text->text.ch + start_pos);
+      text->text.ch[end_pos] = ch;
+    }
+
+  return retval;
+}
+
+
+static void
+gtk_text_destroy (GtkObject *object)
+{
+  GtkText *text;
+  
+  g_return_if_fail (object != NULL);
+  g_return_if_fail (GTK_IS_TEXT (object));
+  
+  text = (GtkText*) object;
+
+  gtk_signal_disconnect_by_data (GTK_OBJECT (text->hadj), text);
+  gtk_signal_disconnect_by_data (GTK_OBJECT (text->vadj), text);
+
+  if (text->timer)
+    {
+      gtk_timeout_remove (text->timer);
+      text->timer = 0;
+    }
+  
+  GTK_OBJECT_CLASS(parent_class)->destroy (object);
+}
+
+static void
+gtk_text_finalize (GtkObject *object)
+{
+  GtkText *text;
+  GList *tmp_list;
+  
+  g_return_if_fail (object != NULL);
+  g_return_if_fail (GTK_IS_TEXT (object));
+  
+  text = (GtkText *)object;
+  
+  gtk_object_unref (GTK_OBJECT (text->hadj));
+  gtk_object_unref (GTK_OBJECT (text->vadj));
+
+  /* Clean up the internal structures */
+  if (text->use_wchar)
+    g_free (text->text.wc);
+  else
+    g_free (text->text.ch);
+  
+  tmp_list = text->text_properties;
+  while (tmp_list)
+    {
+      destroy_text_property (tmp_list->data);
+      tmp_list = tmp_list->next;
+    }
+
+  if (text->current_font)
+    text_font_unref (text->current_font);
+  
+  g_list_free (text->text_properties);
+  
+  if (text->use_wchar)
+    {
+      if (text->scratch_buffer.wc)
+	g_free (text->scratch_buffer.wc);
+    }
+  else
+    {
+      if (text->scratch_buffer.ch)
+	g_free (text->scratch_buffer.ch);
+    }
+  
+  g_list_free (text->tab_stops);
+  
+  GTK_OBJECT_CLASS(parent_class)->finalize (object);
+}
+
+static void
+gtk_text_realize (GtkWidget *widget)
+{
+  GtkText *text;
+  GtkEditable *editable;
+  GdkWindowAttr attributes;
+  gint attributes_mask;
+  
+  g_return_if_fail (widget != NULL);
+  g_return_if_fail (GTK_IS_TEXT (widget));
+  
+  text = GTK_TEXT (widget);
+  editable = GTK_EDITABLE (widget);
+  GTK_WIDGET_SET_FLAGS (text, GTK_REALIZED);
+  
+  attributes.window_type = GDK_WINDOW_CHILD;
+  attributes.x = widget->allocation.x;
+  attributes.y = widget->allocation.y;
+  attributes.width = widget->allocation.width;
+  attributes.height = widget->allocation.height;
+  attributes.wclass = GDK_INPUT_OUTPUT;
+  attributes.visual = gtk_widget_get_visual (widget);
+  attributes.colormap = gtk_widget_get_colormap (widget);
+  attributes.event_mask = gtk_widget_get_events (widget);
+  attributes.event_mask |= (GDK_EXPOSURE_MASK |
+			    GDK_BUTTON_PRESS_MASK |
+			    GDK_BUTTON_RELEASE_MASK |
+			    GDK_BUTTON_MOTION_MASK |
+			    GDK_ENTER_NOTIFY_MASK |
+			    GDK_LEAVE_NOTIFY_MASK |
+			    GDK_KEY_PRESS_MASK);
+  attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
+  
+  widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
+  gdk_window_set_user_data (widget->window, text);
+  
+  attributes.x = (widget->style->klass->xthickness + TEXT_BORDER_ROOM);
+  attributes.y = (widget->style->klass->ythickness + TEXT_BORDER_ROOM);
+  attributes.width = MAX (1, (gint)widget->allocation.width - (gint)attributes.x * 2);
+  attributes.height = MAX (1, (gint)widget->allocation.height - (gint)attributes.y * 2);
+
+  attributes.cursor = gdk_cursor_new (GDK_XTERM);
+  attributes_mask |= GDK_WA_CURSOR;
+  
+  text->text_area = gdk_window_new (widget->window, &attributes, attributes_mask);
+  gdk_window_set_user_data (text->text_area, text);
+
+  gdk_cursor_destroy (attributes.cursor); /* The X server will keep it around as long as necessary */
+  
+  widget->style = gtk_style_attach (widget->style, widget->window);
+  
+  /* Can't call gtk_style_set_background here because it's handled specially */
+  gdk_window_set_background (widget->window, &widget->style->base[GTK_WIDGET_STATE (widget)]);
+  gdk_window_set_background (text->text_area, &widget->style->base[GTK_WIDGET_STATE (widget)]);
+
+  if (widget->style->bg_pixmap[GTK_STATE_NORMAL])
+    text->bg_gc = create_bg_gc (text);
+  
+  text->line_wrap_bitmap = gdk_bitmap_create_from_data (text->text_area,
+							(gchar*) line_wrap_bits,
+							line_wrap_width,
+							line_wrap_height);
+  
+  text->line_arrow_bitmap = gdk_bitmap_create_from_data (text->text_area,
+							 (gchar*) line_arrow_bits,
+							 line_arrow_width,
+							 line_arrow_height);
+  
+  text->gc = gdk_gc_new (text->text_area);
+  gdk_gc_set_exposures (text->gc, TRUE);
+  gdk_gc_set_foreground (text->gc, &widget->style->text[GTK_STATE_NORMAL]);
+  
+#ifdef USE_XIM
+  if (gdk_im_ready () && (editable->ic_attr = gdk_ic_attr_new ()) != NULL)
+    {
+      gint width, height;
+      GdkColormap *colormap;
+      GdkEventMask mask;
+      GdkICAttr *attr = editable->ic_attr;
+      GdkICAttributesType attrmask = GDK_IC_ALL_REQ;
+      GdkIMStyle style;
+      GdkIMStyle supported_style = GDK_IM_PREEDIT_NONE | 
+	                           GDK_IM_PREEDIT_NOTHING |
+	                           GDK_IM_PREEDIT_POSITION |
+	                           GDK_IM_STATUS_NONE |
+	                           GDK_IM_STATUS_NOTHING;
+      
+      if (widget->style && widget->style->font->type != GDK_FONT_FONTSET)
+	supported_style &= ~GDK_IM_PREEDIT_POSITION;
+      
+      attr->style = style = gdk_im_decide_style (supported_style);
+      attr->client_window = text->text_area;
+
+      if ((colormap = gtk_widget_get_colormap (widget)) !=
+	  gtk_widget_get_default_colormap ())
+	{
+	  attrmask |= GDK_IC_PREEDIT_COLORMAP;
+	  attr->preedit_colormap = colormap;
+	}
+
+      switch (style & GDK_IM_PREEDIT_MASK)
+	{
+	case GDK_IM_PREEDIT_POSITION:
+	  if (widget->style && widget->style->font->type != GDK_FONT_FONTSET)
+	    {
+	      g_warning ("over-the-spot style requires fontset");
+	      break;
+	    }
+
+	  attrmask |= GDK_IC_PREEDIT_POSITION_REQ;
+	  gdk_window_get_size (text->text_area, &width, &height);
+	  attr->spot_location.x = 0;
+	  attr->spot_location.y = height;
+	  attr->preedit_area.x = 0;
+	  attr->preedit_area.y = 0;
+	  attr->preedit_area.width = width;
+	  attr->preedit_area.height = height;
+	  attr->preedit_fontset = widget->style->font;
+	  
+	  break;
+	}
+      editable->ic = gdk_ic_new (attr, attrmask);
+      
+      if (editable->ic == NULL)
+	g_warning ("Can't create input context.");
+      else
+	{
+	  mask = gdk_window_get_events (text->text_area);
+	  mask |= gdk_ic_get_events (editable->ic);
+	  gdk_window_set_events (text->text_area, mask);
+	  
+	  if (GTK_WIDGET_HAS_FOCUS (widget))
+	    gdk_im_begin (editable->ic, text->text_area);
+	}
+    }
+#endif
+
+  realize_properties (text);
+  gdk_window_show (text->text_area);
+  init_properties (text);
+
+  if (editable->selection_start_pos != editable->selection_end_pos)
+    gtk_editable_claim_selection (editable, TRUE, GDK_CURRENT_TIME);
+  
+  recompute_geometry (text);
+}
+
+static void 
+gtk_text_style_set (GtkWidget *widget,
+		    GtkStyle  *previous_style)
+{
+  GtkText *text = GTK_TEXT (widget);
+
+  if (GTK_WIDGET_REALIZED (widget))
+    {
+      gdk_window_set_background (widget->window, &widget->style->base[GTK_WIDGET_STATE (widget)]);
+      gdk_window_set_background (text->text_area, &widget->style->base[GTK_WIDGET_STATE (widget)]);
+      
+      if (text->bg_gc)
+	{
+	  gdk_gc_destroy (text->bg_gc);
+	  text->bg_gc = NULL;
+	}
+
+      if (widget->style->bg_pixmap[GTK_STATE_NORMAL])
+	text->bg_gc = create_bg_gc (text);
+
+      recompute_geometry (text);
+    }
+
+  if (text->current_font)
+    text_font_unref (text->current_font);
+  text->current_font = get_text_font (widget->style->font);
+}
+
+static void
+gtk_text_state_changed (GtkWidget   *widget,
+			GtkStateType previous_state)
+{
+  GtkText *text = GTK_TEXT (widget);
+  
+  if (GTK_WIDGET_REALIZED (widget))
+    {
+      gdk_window_set_background (widget->window, &widget->style->base[GTK_WIDGET_STATE (widget)]);
+      gdk_window_set_background (text->text_area, &widget->style->base[GTK_WIDGET_STATE (widget)]);
+    }
+}
+
+static void
+gtk_text_unrealize (GtkWidget *widget)
+{
+  GtkText *text;
+  
+  g_return_if_fail (widget != NULL);
+  g_return_if_fail (GTK_IS_TEXT (widget));
+  
+  text = GTK_TEXT (widget);
+
+#ifdef USE_XIM
+  if (GTK_EDITABLE (widget)->ic)
+    {
+      gdk_ic_destroy (GTK_EDITABLE (widget)->ic);
+      GTK_EDITABLE (widget)->ic = NULL;
+    }
+  if (GTK_EDITABLE (widget)->ic_attr)
+    {
+      gdk_ic_attr_destroy (GTK_EDITABLE (widget)->ic_attr);
+      GTK_EDITABLE (widget)->ic_attr = NULL;
+    }
+#endif
+
+  gdk_window_set_user_data (text->text_area, NULL);
+  gdk_window_destroy (text->text_area);
+  text->text_area = NULL;
+  
+  gdk_gc_destroy (text->gc);
+  text->gc = NULL;
+
+  if (text->bg_gc)
+    {
+      gdk_gc_destroy (text->bg_gc);
+      text->bg_gc = NULL;
+    }
+  
+  gdk_pixmap_unref (text->line_wrap_bitmap);
+  gdk_pixmap_unref (text->line_arrow_bitmap);
+
+  unrealize_properties (text);
+
+  free_cache (text);
+
+  if (GTK_WIDGET_CLASS (parent_class)->unrealize)
+    (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
+}
+
+static void
+clear_focus_area (GtkText *text, gint area_x, gint area_y, gint area_width, gint area_height)
+{
+  GtkWidget *widget = GTK_WIDGET (text);
+  GdkGC *gc;
+  
+  gint ythick = TEXT_BORDER_ROOM + widget->style->klass->ythickness;
+  gint xthick = TEXT_BORDER_ROOM + widget->style->klass->xthickness;
+  
+  gint width, height;
+
+  if (area_width == 0 || area_height == 0)
+    return;
+  
+  if (widget->style->bg_pixmap[GTK_STATE_NORMAL])
+    {
+      gdk_window_get_size (widget->style->bg_pixmap[GTK_STATE_NORMAL], &width, &height);
+      
+      gdk_gc_set_ts_origin (text->bg_gc,
+			    (- (gint)text->first_onscreen_hor_pixel + xthick) % width,
+			    (- (gint)text->first_onscreen_ver_pixel + ythick) % height);
+
+      gc = text->bg_gc;
+    }
+  else
+    gc = widget->style->bg_gc[widget->state];
+
+
+  gdk_draw_rectangle (GTK_WIDGET (text)->window, gc, TRUE,
+		      area_x, area_y, area_width, area_height);
+}
+
+static void
+gtk_text_draw_focus (GtkWidget *widget)
+{
+  GtkText *text;
+  gint width, height;
+  gint x, y;
+  
+  g_return_if_fail (widget != NULL);
+  g_return_if_fail (GTK_IS_TEXT (widget));
+  
+  text = GTK_TEXT (widget);
+  
+  if (GTK_WIDGET_DRAWABLE (widget))
+    {
+      gint ythick = widget->style->klass->ythickness;
+      gint xthick = widget->style->klass->xthickness;
+      gint xextra = TEXT_BORDER_ROOM;
+      gint yextra = TEXT_BORDER_ROOM;
+      
+      TDEBUG (("in gtk_text_draw_focus\n"));
+      
+      x = 0;
+      y = 0;
+      width = widget->allocation.width;
+      height = widget->allocation.height;
+      
+      if (GTK_WIDGET_HAS_FOCUS (widget))
+	{
+	  x += 1;
+	  y += 1;
+	  width -=  2;
+	  height -= 2;
+	  xextra -= 1;
+	  yextra -= 1;
+
+	  gtk_paint_focus (widget->style, widget->window,
+			   NULL, widget, "text",
+			   0, 0,
+			   widget->allocation.width - 1,
+			   widget->allocation.height - 1);
+	}
+
+      gtk_paint_shadow (widget->style, widget->window,
+			GTK_STATE_NORMAL, GTK_SHADOW_IN,
+			NULL, widget, "text",
+			x, y, width, height);
+
+      x += xthick; 
+      y += ythick;
+      width -= 2 * xthick;
+      height -= 2 * ythick;
+      
+      /* top rect */
+      clear_focus_area (text, x, y, width, yextra);
+      /* left rect */
+      clear_focus_area (text, x, y + yextra, 
+			xextra, y + height - 2 * yextra);
+      /* right rect */
+      clear_focus_area (text, x + width - xextra, y + yextra, 
+			xextra, height - 2 * ythick);
+      /* bottom rect */
+      clear_focus_area (text, x, x + height - yextra, width, yextra);
+    }
+  else
+    {
+      TDEBUG (("in gtk_text_draw_focus (undrawable !!!)\n"));
+    }
+}
+
+static void
+gtk_text_size_request (GtkWidget      *widget,
+		       GtkRequisition *requisition)
+{
+  gint xthickness;
+  gint ythickness;
+  gint char_height;
+  gint char_width;
+  
+  g_return_if_fail (widget != NULL);
+  g_return_if_fail (GTK_IS_TEXT (widget));
+  g_return_if_fail (requisition != NULL);
+  
+  xthickness = widget->style->klass->xthickness + TEXT_BORDER_ROOM;
+  ythickness = widget->style->klass->ythickness + TEXT_BORDER_ROOM;
+  
+  char_height = MIN_TEXT_HEIGHT_LINES * (widget->style->font->ascent +
+					 widget->style->font->descent);
+  
+  char_width = MIN_TEXT_WIDTH_LINES * (gdk_text_width (widget->style->font,
+						       "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
+						       26)
+				       / 26);
+  
+  requisition->width  = char_width  + xthickness * 2;
+  requisition->height = char_height + ythickness * 2;
+}
+
+static void
+gtk_text_size_allocate (GtkWidget     *widget,
+			GtkAllocation *allocation)
+{
+  GtkText *text;
+  GtkEditable *editable;
+  
+  g_return_if_fail (widget != NULL);
+  g_return_if_fail (GTK_IS_TEXT (widget));
+  g_return_if_fail (allocation != NULL);
+  
+  text = GTK_TEXT (widget);
+  editable = GTK_EDITABLE (widget);
+  
+  widget->allocation = *allocation;
+  if (GTK_WIDGET_REALIZED (widget))
+    {
+      gdk_window_move_resize (widget->window,
+			      allocation->x, allocation->y,
+			      allocation->width, allocation->height);
+      
+      gdk_window_move_resize (text->text_area,
+			      widget->style->klass->xthickness + TEXT_BORDER_ROOM,
+			      widget->style->klass->ythickness + TEXT_BORDER_ROOM,
+			      MAX (1, (gint)widget->allocation.width - (gint)(widget->style->klass->xthickness +
+							  (gint)TEXT_BORDER_ROOM) * 2),
+			      MAX (1, (gint)widget->allocation.height - (gint)(widget->style->klass->ythickness +
+							   (gint)TEXT_BORDER_ROOM) * 2));
+      
+#ifdef USE_XIM
+      if (editable->ic && (gdk_ic_get_style (editable->ic) & GDK_IM_PREEDIT_POSITION))
+	{
+	  gint width, height;
+	  
+	  gdk_window_get_size (text->text_area, &width, &height);
+	  editable->ic_attr->preedit_area.width = width;
+	  editable->ic_attr->preedit_area.height = height;
+
+	  gdk_ic_set_attr (editable->ic,
+	      		   editable->ic_attr, GDK_IC_PREEDIT_AREA);
+	}
+#endif
+      
+      recompute_geometry (text);
+    }
+}
+
+static void
+gtk_text_draw (GtkWidget    *widget,
+	       GdkRectangle *area)
+{
+  g_return_if_fail (widget != NULL);
+  g_return_if_fail (GTK_IS_TEXT (widget));
+  g_return_if_fail (area != NULL);
+  
+  if (GTK_WIDGET_DRAWABLE (widget))
+    {
+      expose_text (GTK_TEXT (widget), area, TRUE);
+      gtk_widget_draw_focus (widget);
+    }
+}
+
+static gint
+gtk_text_expose (GtkWidget      *widget,
+		 GdkEventExpose *event)
+{
+  g_return_val_if_fail (widget != NULL, FALSE);
+  g_return_val_if_fail (GTK_IS_TEXT (widget), FALSE);
+  g_return_val_if_fail (event != NULL, FALSE);
+  
+  if (event->window == GTK_TEXT (widget)->text_area)
+    {
+      TDEBUG (("in gtk_text_expose (expose)\n"));
+      expose_text (GTK_TEXT (widget), &event->area, TRUE);
+    }
+  else if (event->count == 0)
+    {
+      TDEBUG (("in gtk_text_expose (focus)\n"));
+      gtk_widget_draw_focus (widget);
+    }
+  
+  return FALSE;
+}
+
+static gint
+gtk_text_scroll_timeout (gpointer data)
+{
+  GtkText *text;
+  GdkEventMotion event;
+  gint x, y;
+  GdkModifierType mask;
+  
+  GDK_THREADS_ENTER ();
+
+  text = GTK_TEXT (data);
+  
+  text->timer = 0;
+  gdk_window_get_pointer (text->text_area, &x, &y, &mask);
+  
+  if (mask & (GDK_BUTTON1_MASK | GDK_BUTTON3_MASK))
+    {
+      event.is_hint = 0;
+      event.x = x;
+      event.y = y;
+      event.state = mask;
+      
+      gtk_text_motion_notify (GTK_WIDGET (text), &event);
+    }
+
+  GDK_THREADS_LEAVE ();
+  
+  return FALSE;
+}
+
+static gint
+gtk_text_button_press (GtkWidget      *widget,
+		       GdkEventButton *event)
+{
+  GtkText *text;
+  GtkEditable *editable;
+  static GdkAtom ctext_atom = GDK_NONE;
+  
+  g_return_val_if_fail (widget != NULL, FALSE);
+  g_return_val_if_fail (GTK_IS_TEXT (widget), FALSE);
+  g_return_val_if_fail (event != NULL, FALSE);
+  
+  if (ctext_atom == GDK_NONE)
+    ctext_atom = gdk_atom_intern ("COMPOUND_TEXT", FALSE);
+  
+  text = GTK_TEXT (widget);
+  editable = GTK_EDITABLE (widget);
+  
+  if (text->button && (event->button != text->button))
+    return FALSE;
+  
+  text->button = event->button;
+  
+  if (!GTK_WIDGET_HAS_FOCUS (widget))
+    gtk_widget_grab_focus (widget);
+  
+  if (event->button == 1)
+    {
+      switch (event->type)
+	{
+	case GDK_BUTTON_PRESS:
+	  gtk_grab_add (widget);
+	  
+	  undraw_cursor (text, FALSE);
+	  find_mouse_cursor (text, (gint)event->x, (gint)event->y);
+	  draw_cursor (text, FALSE);
+	  
+	  /* Set it now, so we display things right. We'll unset it
+	   * later if things don't work out */
+	  editable->has_selection = TRUE;
+	  gtk_text_set_selection (GTK_EDITABLE(text),
+				  text->cursor_mark.index,
+				  text->cursor_mark.index);
+	  
+	  break;
+	  
+	case GDK_2BUTTON_PRESS:
+	  gtk_text_select_word (text, event->time);
+	  break;
+	  
+	case GDK_3BUTTON_PRESS:
+	  gtk_text_select_line (text, event->time);
+	  break;
+	  
+	default:
+	  break;
+	}
+    }
+  else if (event->type == GDK_BUTTON_PRESS)
+    {
+      if ((event->button == 2) && editable->editable)
+	{
+	  if (editable->selection_start_pos == editable->selection_end_pos ||
+	      editable->has_selection)
+	    {
+	      undraw_cursor (text, FALSE);
+	      find_mouse_cursor (text, (gint)event->x, (gint)event->y);
+	      draw_cursor (text, FALSE);
+	      
+	    }
+	  
+	  gtk_selection_convert (widget, GDK_SELECTION_PRIMARY,
+				 ctext_atom, event->time);
+	}
+      else
+	{
+	  gtk_grab_add (widget);
+	  
+	  undraw_cursor (text, FALSE);
+	  find_mouse_cursor (text, event->x, event->y);
+	  draw_cursor (text, FALSE);
+	  
+	  gtk_text_set_selection (GTK_EDITABLE(text),
+				  text->cursor_mark.index,
+				  text->cursor_mark.index);
+	  
+	  editable->has_selection = FALSE;
+	  if (gdk_selection_owner_get (GDK_SELECTION_PRIMARY) == widget->window)
+	    gtk_selection_owner_set (NULL, GDK_SELECTION_PRIMARY, event->time);
+	}
+    }
+  
+  return FALSE;
+}
+
+static gint
+gtk_text_button_release (GtkWidget      *widget,
+			 GdkEventButton *event)
+{
+  GtkText *text;
+  GtkEditable *editable;
+  g_return_val_if_fail (widget != NULL, FALSE);
+  g_return_val_if_fail (GTK_IS_TEXT (widget), FALSE);
+  g_return_val_if_fail (event != NULL, FALSE);
+  
+  text = GTK_TEXT (widget);
+  
+  gtk_grab_remove (widget);
+  
+  if (text->button != event->button)
+    return FALSE;
+  
+  text->button = 0;
+  
+  if (text->timer)
+    {
+      gtk_timeout_remove (text->timer);
+      text->timer = 0;
+    }
+  
+  if (event->button == 1)
+    {
+      text = GTK_TEXT (widget);
+      editable = GTK_EDITABLE (widget);
+      
+      gtk_grab_remove (widget);
+      
+      editable->has_selection = FALSE;
+      if (editable->selection_start_pos != editable->selection_end_pos)
+	{
+	  if (gtk_selection_owner_set (widget,
+				       GDK_SELECTION_PRIMARY,
+				       event->time))
+	    editable->has_selection = TRUE;
+	  else
+	    gtk_text_update_text (editable, editable->selection_start_pos,
+				  editable->selection_end_pos);
+	}
+      else
+	{
+	  if (gdk_selection_owner_get (GDK_SELECTION_PRIMARY) == widget->window)
+	    gtk_selection_owner_set (NULL, GDK_SELECTION_PRIMARY, event->time);
+	}
+    }
+  else if (event->button == 3)
+    {
+      gtk_grab_remove (widget);
+    }
+  
+  undraw_cursor (text, FALSE);
+  find_cursor (text, TRUE);
+  draw_cursor (text, FALSE);
+  
+  return FALSE;
+}
+
+static gint
+gtk_text_motion_notify (GtkWidget      *widget,
+			GdkEventMotion *event)
+{
+  GtkText *text;
+  gint x, y;
+  gint height;
+  GdkModifierType mask;
+  
+  g_return_val_if_fail (widget != NULL, FALSE);
+  g_return_val_if_fail (GTK_IS_TEXT (widget), FALSE);
+  g_return_val_if_fail (event != NULL, FALSE);
+  
+  text = GTK_TEXT (widget);
+  
+  x = event->x;
+  y = event->y;
+  mask = event->state;
+  if (event->is_hint || (text->text_area != event->window))
+    {
+      gdk_window_get_pointer (text->text_area, &x, &y, &mask);
+    }
+  
+  if ((text->button == 0) ||
+      !(mask & (GDK_BUTTON1_MASK | GDK_BUTTON3_MASK)))
+    return FALSE;
+  
+  gdk_window_get_size (text->text_area, NULL, &height);
+  
+  if ((y < 0) || (y > height))
+    {
+      if (text->timer == 0)
+	{
+	  text->timer = gtk_timeout_add (SCROLL_TIME, 
+					 gtk_text_scroll_timeout,
+					 text);
+	  
+	  if (y < 0)
+	    scroll_int (text, y/2);
+	  else
+	    scroll_int (text, (y - height)/2);
+	}
+      else
+	return FALSE;
+    }
+  
+  undraw_cursor (GTK_TEXT (widget), FALSE);
+  find_mouse_cursor (GTK_TEXT (widget), x, y);
+  draw_cursor (GTK_TEXT (widget), FALSE);
+  
+  gtk_text_set_selection (GTK_EDITABLE(text), 
+			  GTK_EDITABLE(text)->selection_start_pos,
+			  text->cursor_mark.index);
+  
+  return FALSE;
+}
+
+static void 
+gtk_text_insert_text    (GtkEditable       *editable,
+			 const gchar       *new_text,
+			 gint               new_text_length,
+			 gint              *position)
+{
+  GtkText *text = GTK_TEXT (editable);
+  GdkFont *font;
+  GdkColor *fore, *back;
+
+  TextProperty *property;
+
+  gtk_text_set_point (text, *position);
+
+  property = MARK_CURRENT_PROPERTY (&text->point);
+  font = property->flags & PROPERTY_FONT ? property->font->gdk_font : NULL; 
+  fore = property->flags & PROPERTY_FOREGROUND ? &property->fore_color : NULL; 
+  back = property->flags & PROPERTY_BACKGROUND ? &property->back_color : NULL; 
+  
+  gtk_text_insert (text, font, fore, back, new_text, new_text_length);
+
+  *position = text->point.index;
+}
+
+static void 
+gtk_text_delete_text    (GtkEditable       *editable,
+			 gint               start_pos,
+			 gint               end_pos)
+{
+  GtkText *text;
+  
+  g_return_if_fail (start_pos >= 0);
+  
+  text = GTK_TEXT (editable);
+  
+  gtk_text_set_point (text, start_pos);
+  if (end_pos < 0)
+    end_pos = TEXT_LENGTH (text);
+  
+  if (end_pos > start_pos)
+    gtk_text_forward_delete (text, end_pos - start_pos);
+}
+
+static gint
+gtk_text_key_press (GtkWidget   *widget,
+		    GdkEventKey *event)
+{
+  GtkText *text;
+  GtkEditable *editable;
+  gchar key;
+  gint return_val;
+  gint position;
+  
+  g_return_val_if_fail (widget != NULL, FALSE);
+  g_return_val_if_fail (GTK_IS_TEXT (widget), FALSE);
+  g_return_val_if_fail (event != NULL, FALSE);
+  
+  return_val = FALSE;
+  
+  text = GTK_TEXT (widget);
+  editable = GTK_EDITABLE (widget);
+  
+  key = event->keyval;
+  return_val = TRUE;
+  
+  if ((GTK_EDITABLE(text)->editable == FALSE))
+    {
+      switch (event->keyval)
+	{
+	case GDK_Home:      
+	  if (event->state & GDK_CONTROL_MASK)
+	    scroll_int (text, -text->vadj->value);
+	  else
+	    return_val = FALSE;
+	  break;
+	case GDK_End:
+	  if (event->state & GDK_CONTROL_MASK)
+	    scroll_int (text, +text->vadj->upper); 
+	  else
+	    return_val = FALSE;
+	  break;
+	case GDK_Page_Up:   scroll_int (text, -text->vadj->page_increment); break;
+	case GDK_Page_Down: scroll_int (text, +text->vadj->page_increment); break;
+	case GDK_Up:        scroll_int (text, -KEY_SCROLL_PIXELS); break;
+	case GDK_Down:      scroll_int (text, +KEY_SCROLL_PIXELS); break;
+	case GDK_Return:
+	  if (event->state & GDK_CONTROL_MASK)
+	    gtk_signal_emit_by_name (GTK_OBJECT (text), "activate");
+	  else
+	    return_val = FALSE;
+	  break;
+	default:
+	  return_val = FALSE;
+	  break;
+	}
+    }
+  else
+    {
+      gint extend_selection;
+      gint extend_start;
+      guint initial_pos = editable->current_pos;
+      
+      text->point = find_mark (text, text->cursor_mark.index);
+      
+      extend_selection = event->state & GDK_SHIFT_MASK;
+      extend_start = FALSE;
+      
+      if (extend_selection)
+	{
+	  editable->has_selection = TRUE;
+	  
+	  if (editable->selection_start_pos == editable->selection_end_pos)
+	    {
+	      editable->selection_start_pos = text->point.index;
+	      editable->selection_end_pos = text->point.index;
+	    }
+	  
+	  extend_start = (text->point.index == editable->selection_start_pos);
+	}
+      
+      switch (event->keyval)
+	{
+	case GDK_Home:
+	  if (event->state & GDK_CONTROL_MASK)
+	    move_cursor_buffer_ver (text, -1);
+	  else
+	    gtk_text_move_beginning_of_line (text);
+	  break;
+	case GDK_End:
+	  if (event->state & GDK_CONTROL_MASK)
+	    move_cursor_buffer_ver (text, +1);
+	  else
+	    gtk_text_move_end_of_line (text);
+	  break;
+	case GDK_Page_Up:   move_cursor_page_ver (text, -1); break;
+	case GDK_Page_Down: move_cursor_page_ver (text, +1); break;
+	  /* CUA has Ctrl-Up/Ctrl-Down as paragraph up down */
+	case GDK_Up:        move_cursor_ver (text, -1); break;
+	case GDK_Down:      move_cursor_ver (text, +1); break;
+	case GDK_Left:
+	  if (event->state & GDK_CONTROL_MASK)
+	    gtk_text_move_backward_word (text);
+	  else
+	    move_cursor_hor (text, -1); 
+	  break;
+	case GDK_Right:     
+	  if (event->state & GDK_CONTROL_MASK)
+	    gtk_text_move_forward_word (text);
+	  else
+	    move_cursor_hor (text, +1); 
+	  break;
+	  
+	case GDK_BackSpace:
+	  if (event->state & GDK_CONTROL_MASK)
+	    gtk_text_delete_backward_word (text);
+	  else
+	    gtk_text_delete_backward_character (text);
+	  break;
+	case GDK_Clear:
+	  gtk_text_delete_line (text);
+	  break;
+	case GDK_Insert:
+	  if (event->state & GDK_SHIFT_MASK)
+	    {
+	      extend_selection = FALSE;
+	      gtk_editable_paste_clipboard (editable);
+	    }
+	  else if (event->state & GDK_CONTROL_MASK)
+	    {
+	      gtk_editable_copy_clipboard (editable);
+	    }
+	  else
+	    {
+	      /* gtk_toggle_insert(text) -- IMPLEMENT */
+	    }
+	  break;
+	case GDK_Delete:
+	  if (event->state & GDK_CONTROL_MASK)
+	    gtk_text_delete_forward_word (text);
+	  else if (event->state & GDK_SHIFT_MASK)
+	    {
+	      extend_selection = FALSE;
+	      gtk_editable_cut_clipboard (editable);
+	    }
+	  else
+	    gtk_text_delete_forward_character (text);
+	  break;
+	case GDK_Tab:
+	  position = text->point.index;
+	  gtk_editable_insert_text (editable, "\t", 1, &position);
+	  break;
+	case GDK_Return:
+	  if (event->state & GDK_CONTROL_MASK)
+	    gtk_signal_emit_by_name (GTK_OBJECT (text), "activate");
+	  else
+	    {
+	      position = text->point.index;
+	      gtk_editable_insert_text (editable, "\n", 1, &position);
+	    }
+	  break;
+	case GDK_Escape:
+	  /* Don't insert literally */
+	  return_val = FALSE;
+	  break;
+	  
+	default:
+	  return_val = FALSE;
+	  
+	  if (event->state & GDK_CONTROL_MASK)
+	    {
+	      if ((key >= 'A') && (key <= 'Z'))
+		key -= 'A' - 'a';
+	      
+	      if ((key >= 'a') && (key <= 'z') && control_keys[(int) (key - 'a')])
+		{
+		  (* control_keys[(int) (key - 'a')]) (editable, event->time);
+		  return_val = TRUE;
+		}
+	      
+	      break;
+	    }
+	  else if (event->state & GDK_MOD1_MASK)
+	    {
+	      if ((key >= 'A') && (key <= 'Z'))
+		key -= 'A' - 'a';
+	      
+	      if ((key >= 'a') && (key <= 'z') && alt_keys[(int) (key - 'a')])
+		{
+		  (* alt_keys[(int) (key - 'a')]) (editable, event->time);
+		  return_val = TRUE;
+		}
+	      
+	      break;
+	    }
+	  else if (event->length > 0)
+	    {
+	      extend_selection = FALSE;
+	      
+	      gtk_editable_delete_selection (editable);
+	      position = text->point.index;
+	      gtk_editable_insert_text (editable, event->string, event->length, &position);
+	      
+	      return_val = TRUE;
+	    }
+	  else
+	    return_val = FALSE;
+	}
+      
+      if (return_val && (editable->current_pos != initial_pos))
+	{
+	  if (extend_selection)
+	    {
+	      if (editable->current_pos < editable->selection_start_pos)
+		gtk_text_set_selection (editable, editable->current_pos,
+					editable->selection_end_pos);
+	      else if (editable->current_pos > editable->selection_end_pos)
+		gtk_text_set_selection (editable, editable->selection_start_pos,
+					editable->current_pos);
+	      else
+		{
+		  if (extend_start)
+		    gtk_text_set_selection (editable, editable->current_pos,
+					    editable->selection_end_pos);
+		  else
+		    gtk_text_set_selection (editable, editable->selection_start_pos,
+					    editable->current_pos);
+		}
+	    }
+	  else
+	    gtk_text_set_selection (editable, 0, 0);
+	  
+	  gtk_editable_claim_selection (editable,
+					editable->selection_start_pos != editable->selection_end_pos,
+					event->time);
+	}
+    }
+  
+  return return_val;
+}
+
+static gint
+gtk_text_focus_in (GtkWidget     *widget,
+		   GdkEventFocus *event)
+{
+  g_return_val_if_fail (widget != NULL, FALSE);
+  g_return_val_if_fail (GTK_IS_TEXT (widget), FALSE);
+  g_return_val_if_fail (event != NULL, FALSE);
+  
+  TDEBUG (("in gtk_text_focus_in\n"));
+  
+  GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
+  gtk_widget_draw_focus (widget);
+  
+#ifdef USE_XIM
+  if (GTK_EDITABLE(widget)->ic)
+    gdk_im_begin (GTK_EDITABLE(widget)->ic, GTK_TEXT(widget)->text_area);
+#endif
+  
+  draw_cursor (GTK_TEXT(widget), TRUE);
+  
+  return FALSE;
+}
+
+static gint
+gtk_text_focus_out (GtkWidget     *widget,
+		    GdkEventFocus *event)
+{
+  g_return_val_if_fail (widget != NULL, FALSE);
+  g_return_val_if_fail (GTK_IS_TEXT (widget), FALSE);
+  g_return_val_if_fail (event != NULL, FALSE);
+  
+  TDEBUG (("in gtk_text_focus_out\n"));
+  
+  GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
+  gtk_widget_draw_focus (widget);
+  
+  undraw_cursor (GTK_TEXT(widget), TRUE);
+  
+#ifdef USE_XIM
+  gdk_im_end ();
+#endif
+  
+  return FALSE;
+}
+
+static void
+gtk_text_adjustment (GtkAdjustment *adjustment,
+		     GtkText       *text)
+{
+  gfloat old_val;
+  
+  g_return_if_fail (adjustment != NULL);
+  g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
+  g_return_if_fail (text != NULL);
+  g_return_if_fail (GTK_IS_TEXT (text));
+
+  /* Clamp the value here, because we'll get really confused
+   * if someone tries to move the adjusment outside of the
+   * allowed bounds
+   */
+  old_val = adjustment->value;
+
+  adjustment->value = MIN (adjustment->value, adjustment->upper - adjustment->page_size);
+  adjustment->value = MAX (adjustment->value, 0.0);
+
+  if (adjustment->value != old_val)
+    {
+      gtk_signal_handler_block_by_func (GTK_OBJECT (adjustment),
+					GTK_SIGNAL_FUNC (gtk_text_adjustment),
+					text);
+      gtk_adjustment_changed (adjustment);
+      gtk_signal_handler_unblock_by_func (GTK_OBJECT (adjustment),
+					  GTK_SIGNAL_FUNC (gtk_text_adjustment),
+					  text);
+    }
+  
+  /* Just ignore it if we haven't been size-allocated and realized yet */
+  if (text->line_start_cache == NULL) 
+    return;
+  
+  if (adjustment == text->hadj)
+    {
+      g_warning ("horizontal scrolling not implemented");
+    }
+  else
+    {
+      gint diff = ((gint)adjustment->value) - text->last_ver_value;
+      
+      if (diff != 0)
+	{
+	  undraw_cursor (text, FALSE);
+	  
+	  if (diff > 0)
+	    scroll_down (text, diff);
+	  else /* if (diff < 0) */
+	    scroll_up (text, diff);
+	  
+	  draw_cursor (text, FALSE);
+	  
+	  text->last_ver_value = adjustment->value;
+	}
+    }
+}
+
+static void
+gtk_text_disconnect (GtkAdjustment *adjustment,
+		     GtkText       *text)
+{
+  g_return_if_fail (adjustment != NULL);
+  g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
+  g_return_if_fail (text != NULL);
+  g_return_if_fail (GTK_IS_TEXT (text));
+
+  if (adjustment == text->hadj)
+    gtk_text_set_adjustments (text, NULL, text->vadj);
+  if (adjustment == text->vadj)
+    gtk_text_set_adjustments (text, text->hadj, NULL);
+}
+
+
+static GtkPropertyMark
+find_this_line_start_mark (GtkText* text, guint point_position, const GtkPropertyMark* near)
+{
+  GtkPropertyMark mark;
+  
+  mark = find_mark_near (text, point_position, near);
+  
+  while (mark.index > 0 &&
+	 GTK_TEXT_INDEX (text, mark.index - 1) != LINE_DELIM)
+    decrement_mark (&mark);
+  
+  return mark;
+}
+
+static void
+init_tab_cont (GtkText* text, PrevTabCont* tab_cont)
+{
+  tab_cont->pixel_offset          = 0;
+  tab_cont->tab_start.tab_stops   = text->tab_stops;
+  tab_cont->tab_start.to_next_tab = (gulong) text->tab_stops->data;
+  
+  if (!tab_cont->tab_start.to_next_tab)
+    tab_cont->tab_start.to_next_tab = text->default_tab_width;
+}
+
+static void
+line_params_iterate (GtkText* text,
+		     const GtkPropertyMark* mark0,
+		     const PrevTabCont* tab_mark0,
+		     gint8 alloc,
+		     void* data,
+		     LineIteratorFunction iter)
+     /* mark0 MUST be a real line start.  if ALLOC, allocate line params
+      * from a mem chunk.  DATA is passed to ITER_CALL, which is called
+      * for each line following MARK, iteration continues unless ITER_CALL
+      * returns TRUE. */
+{
+  GtkPropertyMark mark = *mark0;
+  PrevTabCont  tab_conts[2];
+  LineParams   *lp, lpbuf;
+  gint         tab_cont_index = 0;
+  
+  if (tab_mark0)
+    tab_conts[0] = *tab_mark0;
+  else
+    init_tab_cont (text, tab_conts);
+  
+  for (;;)
+    {
+      if (alloc)
+	lp = g_chunk_new (LineParams, params_mem_chunk);
+      else
+	lp = &lpbuf;
+      
+      *lp = find_line_params (text, &mark, tab_conts + tab_cont_index,
+			      tab_conts + (tab_cont_index + 1) % 2);
+      
+      if ((*iter) (text, lp, data))
+	return;
+      
+      if (LAST_INDEX (text, lp->end))
+	break;
+      
+      mark = lp->end;
+      advance_mark (&mark);
+      tab_cont_index = (tab_cont_index + 1) % 2;
+    }
+}
+
+static gint
+fetch_lines_iterator (GtkText* text, LineParams* lp, void* data)
+{
+  FetchLinesData *fldata = (FetchLinesData*) data;
+  
+  fldata->new_lines = g_list_prepend (fldata->new_lines, lp);
+  
+  switch (fldata->fl_type)
+    {
+    case FetchLinesCount:
+      if (!text->line_wrap || !lp->wraps)
+	fldata->data += 1;
+      
+      if (fldata->data >= fldata->data_max)
+	return TRUE;
+      
+      break;
+    case FetchLinesPixels:
+      
+      fldata->data += LINE_HEIGHT(*lp);
+      
+      if (fldata->data >= fldata->data_max)
+	return TRUE;
+      
+      break;
+    }
+  
+  return FALSE;
+}
+
+static GList*
+fetch_lines (GtkText* text,
+	     const GtkPropertyMark* mark0,
+	     const PrevTabCont* tab_cont0,
+	     FLType fl_type,
+	     gint data)
+{
+  FetchLinesData fl_data;
+  
+  fl_data.new_lines = NULL;
+  fl_data.data      = 0;
+  fl_data.data_max  = data;
+  fl_data.fl_type   = fl_type;
+  
+  line_params_iterate (text, mark0, tab_cont0, TRUE, &fl_data, fetch_lines_iterator);
+  
+  return g_list_reverse (fl_data.new_lines);
+}
+
+static void
+fetch_lines_backward (GtkText* text)
+{
+  GList* new_lines = NULL, *new_line_start;
+  GtkPropertyMark mark;
+  
+  if (CACHE_DATA(text->line_start_cache).start.index == 0)
+    return;
+  
+  mark = find_this_line_start_mark (text,
+				    CACHE_DATA(text->line_start_cache).start.index - 1,
+				    &CACHE_DATA(text->line_start_cache).start);
+  
+  new_line_start = new_lines = fetch_lines (text, &mark, NULL, FetchLinesCount, 1);
+  
+  while (new_line_start->next)
+    new_line_start = new_line_start->next;
+  
+  new_line_start->next = text->line_start_cache;
+  text->line_start_cache->prev = new_line_start;
+}
+
+static void
+fetch_lines_forward (GtkText* text, gint line_count)
+{
+  GtkPropertyMark mark;
+  GList* line = text->line_start_cache;
+  
+  while(line->next)
+    line = line->next;
+  
+  mark = CACHE_DATA(line).end;
+  
+  if (LAST_INDEX (text, mark))
+    return;
+  
+  advance_mark(&mark);
+  
+  line->next = fetch_lines (text, &mark, &CACHE_DATA(line).tab_cont_next, FetchLinesCount, line_count);
+  
+  if (line->next)
+    line->next->prev = line;
+}
+
+/* Compute the number of lines, and vertical pixels for n characters
+ * starting from the point 
+ */
+static void
+compute_lines_pixels (GtkText* text, guint char_count,
+		      guint *lines, guint *pixels)
+{
+  GList *line = text->current_line;
+  gint chars_left = char_count;
+  
+  *lines = 0;
+  *pixels = 0;
+  
+  /* If chars_left == 0, that means we're joining two lines in a
+   * deletion, so add in the values for the next line as well 
+   */
+  for (; line && chars_left >= 0; line = line->next)
+    {
+      *pixels += LINE_HEIGHT(CACHE_DATA(line));
+      
+      if (line == text->current_line)
+	chars_left -= CACHE_DATA(line).end.index - text->point.index + 1;
+      else
+	chars_left -= CACHE_DATA(line).end.index - CACHE_DATA(line).start.index + 1;
+      
+      if (!text->line_wrap || !CACHE_DATA(line).wraps)
+	*lines += 1;
+      else
+	if (chars_left < 0)
+	  chars_left = 0;	/* force another loop */
+      
+      if (!line->next)
+	fetch_lines_forward (text, 1);
+    }
+}
+
+static gint
+total_line_height (GtkText* text, GList* line, gint line_count)
+{
+  gint height = 0;
+  
+  for (; line && line_count > 0; line = line->next)
+    {
+      height += LINE_HEIGHT(CACHE_DATA(line));
+      
+      if (!text->line_wrap || !CACHE_DATA(line).wraps)
+	line_count -= 1;
+      
+      if (!line->next)
+	fetch_lines_forward (text, line_count);
+    }
+  
+  return height;
+}
+
+static void
+swap_lines (GtkText* text, GList* old, GList* new, guint old_line_count)
+{
+  if (old == text->line_start_cache)
+    {
+      GList* last;
+      
+      for (; old_line_count > 0; old_line_count -= 1)
+	{
+	  while (text->line_start_cache &&
+		 text->line_wrap &&
+		 CACHE_DATA(text->line_start_cache).wraps)
+	    remove_cache_line(text, text->line_start_cache);
+	  
+	  remove_cache_line(text, text->line_start_cache);
+	}
+      
+      last = g_list_last (new);
+      
+      last->next = text->line_start_cache;
+      
+      if (text->line_start_cache)
+	text->line_start_cache->prev = last;
+      
+      text->line_start_cache = new;
+    }
+  else
+    {
+      GList *last;
+      
+      g_assert (old->prev);
+      
+      last = old->prev;
+      
+      for (; old_line_count > 0; old_line_count -= 1)
+	{
+	  while (old && text->line_wrap && CACHE_DATA(old).wraps)
+	    old = remove_cache_line (text, old);
+	  
+	  old = remove_cache_line (text, old);
+	}
+      
+      last->next = new;
+      new->prev = last;
+      
+      last = g_list_last (new);
+      
+      last->next = old;
+      
+      if (old)
+	old->prev = last;
+    }
+}
+
+static void
+correct_cache_delete (GtkText* text, gint nchars, gint lines)
+{
+  GList* cache = text->current_line;
+  gint i;
+  
+  for (i = 0; cache && i < lines; i += 1, cache = cache->next)
+    /* nothing */;
+  
+  for (; cache; cache = cache->next)
+    {
+      GtkPropertyMark *start = &CACHE_DATA(cache).start;
+      GtkPropertyMark *end = &CACHE_DATA(cache).end;
+      
+      start->index -= nchars;
+      end->index -= nchars;
+      
+      if (LAST_INDEX (text, text->point) &&
+	  start->index == text->point.index)
+	*start = text->point;
+      else if (start->property == text->point.property)
+	start->offset = start->index - (text->point.index - text->point.offset);
+      
+      if (LAST_INDEX (text, text->point) &&
+	  end->index == text->point.index)
+	*end = text->point;
+      if (end->property == text->point.property)
+	end->offset = end->index - (text->point.index - text->point.offset);
+      
+      /*TEXT_ASSERT_MARK(text, start, "start");*/
+      /*TEXT_ASSERT_MARK(text, end, "end");*/
+    }
+}
+
+static void
+delete_expose (GtkText* text, guint nchars, guint old_lines, guint old_pixels)
+{
+  GtkWidget *widget = GTK_WIDGET (text);
+  
+  gint pixel_height;
+  guint new_pixels = 0;
+  GdkRectangle rect;
+  GList* new_line = NULL;
+  gint width, height;
+  
+  text->cursor_virtual_x = 0;
+  
+  correct_cache_delete (text, nchars, old_lines);
+  
+  pixel_height = pixel_height_of(text, text->current_line) -
+    LINE_HEIGHT(CACHE_DATA(text->current_line));
+  
+  if (CACHE_DATA(text->current_line).start.index == text->point.index)
+    CACHE_DATA(text->current_line).start = text->point;
+  
+  new_line = fetch_lines (text,
+			  &CACHE_DATA(text->current_line).start,
+			  &CACHE_DATA(text->current_line).tab_cont,
+			  FetchLinesCount,
+			  1);
+  
+  swap_lines (text, text->current_line, new_line, old_lines);
+  
+  text->current_line = new_line;
+  
+  new_pixels = total_line_height (text, new_line, 1);
+  
+  gdk_window_get_size (text->text_area, &width, &height);
+  
+  if (old_pixels != new_pixels)
+    {
+      if (!widget->style->bg_pixmap[GTK_STATE_NORMAL])
+	{
+	  gdk_draw_pixmap (text->text_area,
+			   text->gc,
+			   text->text_area,
+			   0,
+			   pixel_height + old_pixels,
+			   0,
+			   pixel_height + new_pixels,
+			   width,
+			   height);
+	}
+      text->vadj->upper += new_pixels;
+      text->vadj->upper -= old_pixels;
+      adjust_adj (text, text->vadj);
+    }
+  
+  rect.x = 0;
+  rect.y = pixel_height;
+  rect.width = width;
+  rect.height = new_pixels;
+  
+  expose_text (text, &rect, FALSE);
+  gtk_text_draw_focus ( (GtkWidget *) text);
+  
+  text->cursor_mark = text->point;
+  
+  find_cursor (text, TRUE);
+  
+  if (old_pixels != new_pixels)
+    {
+      if (widget->style->bg_pixmap[GTK_STATE_NORMAL])
+	{
+	  rect.x = 0;
+	  rect.y = pixel_height + new_pixels;
+	  rect.width = width;
+	  rect.height = height - rect.y;
+	  
+	  expose_text (text, &rect, FALSE);
+	}
+      else
+	process_exposes (text);
+    }
+  
+  TEXT_ASSERT (text);
+  TEXT_SHOW(text);
+}
+
+/* note, the point has already been moved forward */
+static void
+correct_cache_insert (GtkText* text, gint nchars)
+{
+  GList *cache;
+  GtkPropertyMark *start;
+  GtkPropertyMark *end;
+  
+  /* If we inserted a property exactly at the beginning of the
+   * line, we have to correct here, or fetch_lines will
+   * fetch junk.
+   */
+  start = &CACHE_DATA(text->current_line).start;
+  if (start->index == text->point.index - nchars)
+    {
+      *start = text->point;
+      move_mark_n (start, -nchars);
+    }
+
+  /* Now correct the offsets, and check for start or end marks that
+   * are after the point, yet point to a property before the point's
+   * property. This indicates that they are meant to point to the
+   * second half of a property we split in insert_text_property(), so
+   * we fix them up that way.  
+   */
+  cache = text->current_line->next;
+  
+  for (; cache; cache = cache->next)
+    {
+      start = &CACHE_DATA(cache).start;
+      end = &CACHE_DATA(cache).end;
+      
+      if (LAST_INDEX (text, text->point) &&
+	  start->index == text->point.index)
+	*start = text->point;
+      else
+	{
+	  if (start->property == text->point.property)
+	    {
+	      start->offset += nchars;
+	      start->index += nchars;
+	    }
+	  else if (start->property->next &&
+		   (start->property->next->next == text->point.property))
+	    {
+	      /* We split the property, and this is the second half */
+	      start->offset -= MARK_CURRENT_PROPERTY (start)->length;
+	      start->index += nchars;
+	      start->property = text->point.property;
+	    }
+	  else
+	    start->index += nchars;
+	}
+      
+      if (LAST_INDEX (text, text->point) &&
+	  end->index == text->point.index)
+	*end = text->point;
+      else
+	{
+	  if (end->property == text->point.property)
+	    {
+	      end->offset += nchars;
+	      end->index += nchars;
+	    }
+	  else if (end->property->next &&
+		   (end->property->next->next == text->point.property))
+	    {
+	      /* We split the property, and this is the second half */
+	      end->offset -= MARK_CURRENT_PROPERTY (end)->length;
+	      end->index += nchars;
+	      end->property = text->point.property;
+	    }
+	  else
+	    end->index += nchars;
+	}
+      
+      /*TEXT_ASSERT_MARK(text, start, "start");*/
+      /*TEXT_ASSERT_MARK(text, end, "end");*/
+    }
+}
+
+
+static void
+insert_expose (GtkText* text, guint old_pixels, gint nchars,
+	       guint new_line_count)
+{
+  GtkWidget *widget = GTK_WIDGET (text);
+  
+  gint pixel_height;
+  guint new_pixels = 0;
+  GdkRectangle rect;
+  GList* new_lines = NULL;
+  gint width, height;
+  
+  text->cursor_virtual_x = 0;
+  
+  undraw_cursor (text, FALSE);
+  
+  correct_cache_insert (text, nchars);
+  
+  TEXT_SHOW_ADJ (text, text->vadj, "vadj");
+  
+  pixel_height = pixel_height_of(text, text->current_line) -
+    LINE_HEIGHT(CACHE_DATA(text->current_line));
+  
+  new_lines = fetch_lines (text,
+			   &CACHE_DATA(text->current_line).start,
+			   &CACHE_DATA(text->current_line).tab_cont,
+			   FetchLinesCount,
+			   new_line_count);
+  
+  swap_lines (text, text->current_line, new_lines, 1);
+  
+  text->current_line = new_lines;
+  
+  new_pixels = total_line_height (text, new_lines, new_line_count);
+  
+  gdk_window_get_size (text->text_area, &width, &height);
+  
+  if (old_pixels != new_pixels)
+    {
+      if (!widget->style->bg_pixmap[GTK_STATE_NORMAL])
+	{
+	  gdk_draw_pixmap (text->text_area,
+			   text->gc,
+			   text->text_area,
+			   0,
+			   pixel_height + old_pixels,
+			   0,
+			   pixel_height + new_pixels,
+			   width,
+			   height + (old_pixels - new_pixels) - pixel_height);
+	  
+	}
+      text->vadj->upper += new_pixels;
+      text->vadj->upper -= old_pixels;
+      adjust_adj (text, text->vadj);
+    }
+  
+  rect.x = 0;
+  rect.y = pixel_height;
+  rect.width = width;
+  rect.height = new_pixels;
+  
+  expose_text (text, &rect, FALSE);
+  gtk_text_draw_focus ( (GtkWidget *) text);
+  
+  text->cursor_mark = text->point;
+  
+  find_cursor (text, TRUE);
+  
+  draw_cursor (text, FALSE);
+  
+  if (old_pixels != new_pixels)
+    {
+      if (widget->style->bg_pixmap[GTK_STATE_NORMAL])
+	{
+	  rect.x = 0;
+	  rect.y = pixel_height + new_pixels;
+	  rect.width = width;
+	  rect.height = height - rect.y;
+	  
+	  expose_text (text, &rect, FALSE);
+	}
+      else
+	process_exposes (text);
+    }
+  
+  TEXT_SHOW_ADJ (text, text->vadj, "vadj");
+  TEXT_ASSERT (text);
+  TEXT_SHOW(text);
+}
+
+/* Text property functions */
+
+static guint
+font_hash (gconstpointer font)
+{
+  return gdk_font_id ((const GdkFont*) font);
+}
+
+static GHashTable *font_cache_table = NULL;
+
+static GtkTextFont*
+get_text_font (GdkFont* gfont)
+{
+  GtkTextFont* tf;
+  gint i;
+  
+  if (!font_cache_table)
+    font_cache_table = g_hash_table_new (font_hash, (GCompareFunc) gdk_font_equal);
+  
+  tf = g_hash_table_lookup (font_cache_table, gfont);
+  
+  if (tf)
+    {
+      tf->ref_count++;
+      return tf;
+    }
+
+  tf = g_new (GtkTextFont, 1);
+  tf->ref_count = 1;
+
+  tf->gdk_font = gfont;
+  gdk_font_ref (gfont);
+  
+  for(i = 0; i < 256; i += 1)
+    tf->char_widths[i] = gdk_char_width (gfont, (char)i);
+  
+  g_hash_table_insert (font_cache_table, gfont, tf);
+  
+  return tf;
+}
+
+static void
+text_font_unref (GtkTextFont *text_font)
+{
+  text_font->ref_count--;
+  if (text_font->ref_count == 0)
+    {
+      g_hash_table_remove (font_cache_table, text_font->gdk_font);
+      gdk_font_unref (text_font->gdk_font);
+      g_free (text_font);
+    }
+}
+
+static gint
+text_properties_equal (TextProperty* prop, GdkFont* font, GdkColor *fore, GdkColor *back)
+{
+  if (prop->flags & PROPERTY_FONT)
+    {
+      gboolean retval;
+      GtkTextFont *text_font;
+
+      if (!font)
+	return FALSE;
+
+      text_font = get_text_font (font);
+
+      retval = (prop->font == text_font);
+      text_font_unref (text_font);
+      
+      if (!retval)
+	return FALSE;
+    }
+  else
+    if (font != NULL)
+      return FALSE;
+
+  if (prop->flags & PROPERTY_FOREGROUND)
+    {
+      if (!fore || !gdk_color_equal (&prop->fore_color, fore))
+	return FALSE;
+    }
+  else
+    if (fore != NULL)
+      return FALSE;
+
+  if (prop->flags & PROPERTY_BACKGROUND)
+    {
+      if (!back || !gdk_color_equal (&prop->back_color, back))
+	return FALSE;
+    }
+  else
+    if (back != NULL)
+      return FALSE;
+  
+  return TRUE;
+}
+
+static void
+realize_property (GtkText *text, TextProperty *prop)
+{
+  GdkColormap *colormap = gtk_widget_get_colormap (GTK_WIDGET (text));
+
+  if (prop->flags & PROPERTY_FOREGROUND)
+    gdk_colormap_alloc_color (colormap, &prop->fore_color, FALSE, FALSE);
+  
+  if (prop->flags & PROPERTY_BACKGROUND)
+    gdk_colormap_alloc_color (colormap, &prop->back_color, FALSE, FALSE);
+}
+
+static void
+realize_properties (GtkText *text)
+{
+  GList *tmp_list = text->text_properties;
+
+  while (tmp_list)
+    {
+      realize_property (text, tmp_list->data);
+      
+      tmp_list = tmp_list->next;
+    }
+}
+
+static void
+unrealize_property (GtkText *text, TextProperty *prop)
+{
+  GdkColormap *colormap = gtk_widget_get_colormap (GTK_WIDGET (text));
+
+  if (prop->flags & PROPERTY_FOREGROUND)
+    gdk_colormap_free_colors (colormap, &prop->fore_color, 1);
+  
+  if (prop->flags & PROPERTY_BACKGROUND)
+    gdk_colormap_free_colors (colormap, &prop->back_color, 1);
+}
+
+static void
+unrealize_properties (GtkText *text)
+{
+  GList *tmp_list = text->text_properties;
+
+  while (tmp_list)
+    {
+      unrealize_property (text, tmp_list->data);
+
+      tmp_list = tmp_list->next;
+    }
+}
+
+static TextProperty*
+new_text_property (GtkText *text, GdkFont *font, GdkColor* fore, 
+		   GdkColor* back, guint length)
+{
+  TextProperty *prop;
+  
+  if (text_property_chunk == NULL)
+    {
+      text_property_chunk = g_mem_chunk_new ("text property mem chunk",
+					     sizeof(TextProperty),
+					     1024*sizeof(TextProperty),
+					     G_ALLOC_AND_FREE);
+    }
+  
+  prop = g_chunk_new(TextProperty, text_property_chunk);
+
+  prop->flags = 0;
+  if (font)
+    {
+      prop->flags |= PROPERTY_FONT;
+      prop->font = get_text_font (font);
+    }
+  else
+    prop->font = NULL;
+  
+  if (fore)
+    {
+      prop->flags |= PROPERTY_FOREGROUND;
+      prop->fore_color = *fore;
+    }
+      
+  if (back)
+    {
+      prop->flags |= PROPERTY_BACKGROUND;
+      prop->back_color = *back;
+    }
+
+  prop->length = length;
+
+  if (GTK_WIDGET_REALIZED (text))
+    realize_property (text, prop);
+
+  return prop;
+}
+
+static void
+destroy_text_property (TextProperty *prop)
+{
+  if (prop->font)
+    text_font_unref (prop->font);
+  
+  g_mem_chunk_free (text_property_chunk, prop);
+}
+
+/* Flop the memory between the point and the gap around like a
+ * dead fish. */
+static void
+move_gap (GtkText* text, guint index)
+{
+  if (text->gap_position < index)
+    {
+      gint diff = index - text->gap_position;
+      
+      if (text->use_wchar)
+	g_memmove (text->text.wc + text->gap_position,
+		   text->text.wc + text->gap_position + text->gap_size,
+		   diff*sizeof (GdkWChar));
+      else
+	g_memmove (text->text.ch + text->gap_position,
+		   text->text.ch + text->gap_position + text->gap_size,
+		   diff);
+      
+      text->gap_position = index;
+    }
+  else if (text->gap_position > index)
+    {
+      gint diff = text->gap_position - index;
+      
+      if (text->use_wchar)
+	g_memmove (text->text.wc + index + text->gap_size,
+		   text->text.wc + index,
+		   diff*sizeof (GdkWChar));
+      else
+	g_memmove (text->text.ch + index + text->gap_size,
+		   text->text.ch + index,
+		   diff);
+      
+      text->gap_position = index;
+    }
+}
+
+/* Increase the gap size. */
+static void
+make_forward_space (GtkText* text, guint len)
+{
+  if (text->gap_size < len)
+    {
+      guint sum = MAX(2*len, MIN_GAP_SIZE) + text->text_end;
+      
+      if (sum >= text->text_len)
+	{
+	  guint i = 1;
+	  
+	  while (i <= sum) i <<= 1;
+	  
+	  if (text->use_wchar)
+	    text->text.wc = (GdkWChar *)g_realloc(text->text.wc,
+						  i*sizeof(GdkWChar));
+	  else
+	    text->text.ch = (guchar *)g_realloc(text->text.ch, i);
+	  text->text_len = i;
+	}
+      
+      if (text->use_wchar)
+	g_memmove (text->text.wc + text->gap_position + text->gap_size + 2*len,
+		   text->text.wc + text->gap_position + text->gap_size,
+		   (text->text_end - (text->gap_position + text->gap_size))
+		   *sizeof(GdkWChar));
+      else
+	g_memmove (text->text.ch + text->gap_position + text->gap_size + 2*len,
+		   text->text.ch + text->gap_position + text->gap_size,
+		   text->text_end - (text->gap_position + text->gap_size));
+      
+      text->text_end += len*2;
+      text->gap_size += len*2;
+    }
+}
+
+/* Inserts into the text property list a list element that guarantees
+ * that for len characters following the point, text has the correct
+ * property.  does not move point.  adjusts text_properties_point and
+ * text_properties_point_offset relative to the current value of
+ * point. */
+static void
+insert_text_property (GtkText* text, GdkFont* font,
+		      GdkColor *fore, GdkColor* back, guint len)
+{
+  GtkPropertyMark *mark = &text->point;
+  TextProperty* forward_prop = MARK_CURRENT_PROPERTY(mark);
+  TextProperty* backward_prop = MARK_PREV_PROPERTY(mark);
+  
+  if (MARK_OFFSET(mark) == 0)
+    {
+      /* Point is on the boundary of two properties.
+       * If it is the same as either, grow, else insert
+       * a new one. */
+      
+      if (text_properties_equal(forward_prop, font, fore, back))
+	{
+	  /* Grow the property in front of us. */
+	  
+	  MARK_PROPERTY_LENGTH(mark) += len;
+	}
+      else if (backward_prop &&
+	       text_properties_equal(backward_prop, font, fore, back))
+	{
+	  /* Grow property behind us, point property and offset
+	   * change. */
+	  
+	  SET_PROPERTY_MARK (&text->point,
+			     MARK_PREV_LIST_PTR (mark),
+			     backward_prop->length);
+	  
+	  backward_prop->length += len;
+	}
+      else if ((MARK_NEXT_LIST_PTR(mark) == NULL) &&
+	       (forward_prop->length == 1))
+	{
+	  /* Next property just has last position, take it over */
+
+	  if (GTK_WIDGET_REALIZED (text))
+	    unrealize_property (text, forward_prop);
+
+	  forward_prop->flags = 0;
+	  if (font)
+	    {
+	      forward_prop->flags |= PROPERTY_FONT;
+	      forward_prop->font = get_text_font (font);
+	    }
+	  else
+	    forward_prop->font = NULL;
+	    
+	  if (fore)
+	    {
+	      forward_prop->flags |= PROPERTY_FOREGROUND;
+	      forward_prop->fore_color = *fore;
+	    }
+	  if (back)
+	    {
+	      forward_prop->flags |= PROPERTY_BACKGROUND;
+	      forward_prop->back_color = *back;
+	    }
+	  forward_prop->length += len;
+
+	  if (GTK_WIDGET_REALIZED (text))
+	    realize_property (text, forward_prop);
+	}
+      else
+	{
+	  /* Splice a new property into the list. */
+	  
+	  GList* new_prop = g_list_alloc();
+	  
+	  new_prop->next = MARK_LIST_PTR(mark);
+	  new_prop->prev = MARK_PREV_LIST_PTR(mark);
+	  new_prop->next->prev = new_prop;
+	  
+	  if (new_prop->prev)
+	    new_prop->prev->next = new_prop;
+
+	  new_prop->data = new_text_property (text, font, fore, back, len);
+
+	  SET_PROPERTY_MARK (mark, new_prop, 0);
+	}
+    }
+  else
+    {
+      /* The following will screw up the line_start cache,
+       * we'll fix it up in correct_cache_insert
+       */
+      
+      /* In the middle of forward_prop, if properties are equal,
+       * just add to its length, else split it into two and splice
+       * in a new one. */
+      if (text_properties_equal (forward_prop, font, fore, back))
+	{
+	  forward_prop->length += len;
+	}
+      else if ((MARK_NEXT_LIST_PTR(mark) == NULL) &&
+	       (MARK_OFFSET(mark) + 1 == forward_prop->length))
+	{
+	  /* Inserting before only the last position in the text */
+	  
+	  GList* new_prop;
+	  forward_prop->length -= 1;
+	  
+	  new_prop = g_list_alloc();
+	  new_prop->data = new_text_property (text, font, fore, back, len+1);
+	  new_prop->prev = MARK_LIST_PTR(mark);
+	  new_prop->next = NULL;
+	  MARK_NEXT_LIST_PTR(mark) = new_prop;
+	  
+	  SET_PROPERTY_MARK (mark, new_prop, 0);
+	}
+      else
+	{
+	  GList* new_prop = g_list_alloc();
+	  GList* new_prop_forward = g_list_alloc();
+	  gint old_length = forward_prop->length;
+	  GList* next = MARK_NEXT_LIST_PTR(mark);
+	  
+	  /* Set the new lengths according to where they are split.  Construct
+	   * two new properties. */
+	  forward_prop->length = MARK_OFFSET(mark);
+
+	  new_prop_forward->data = 
+	    new_text_property(text,
+			      forward_prop->flags & PROPERTY_FONT ? 
+                                     forward_prop->font->gdk_font : NULL,
+			      forward_prop->flags & PROPERTY_FOREGROUND ? 
+  			             &forward_prop->fore_color : NULL,
+			      forward_prop->flags & PROPERTY_BACKGROUND ? 
+  			             &forward_prop->back_color : NULL,
+			      old_length - forward_prop->length);
+
+	  new_prop->data = new_text_property(text, font, fore, back, len);
+
+	  /* Now splice things in. */
+	  MARK_NEXT_LIST_PTR(mark) = new_prop;
+	  new_prop->prev = MARK_LIST_PTR(mark);
+	  
+	  new_prop->next = new_prop_forward;
+	  new_prop_forward->prev = new_prop;
+	  
+	  new_prop_forward->next = next;
+	  
+	  if (next)
+	    next->prev = new_prop_forward;
+	  
+	  SET_PROPERTY_MARK (mark, new_prop, 0);
+	}
+    }
+  
+  while (text->text_properties_end->next)
+    text->text_properties_end = text->text_properties_end->next;
+  
+  while (text->text_properties->prev)
+    text->text_properties = text->text_properties->prev;
+}
+
+static void
+delete_text_property (GtkText* text, guint nchars)
+{
+  /* Delete nchars forward from point. */
+  
+  /* Deleting text properties is problematical, because we
+   * might be storing around marks pointing to a property.
+   *
+   * The marks in question and how we handle them are:
+   *
+   *  point: We know the new value, since it will be at the
+   *         end of the deleted text, and we move it there
+   *         first.
+   *  cursor: We just remove the mark and set it equal to the
+   *         point after the operation.
+   *  line-start cache: We replace most affected lines.
+   *         The current line gets used to fetch the new
+   *         lines so, if necessary, (delete at the beginning
+   *         of a line) we fix it up by setting it equal to the
+   *         point.
+   */
+  
+  TextProperty *prop;
+  GList        *tmp;
+  gint          is_first;
+  
+  for(; nchars; nchars -= 1)
+    {
+      prop = MARK_CURRENT_PROPERTY(&text->point);
+      
+      prop->length -= 1;
+      
+      if (prop->length == 0)
+	{
+	  tmp = MARK_LIST_PTR (&text->point);
+	  
+	  is_first = tmp == text->text_properties;
+	  
+	  MARK_LIST_PTR (&text->point) = g_list_remove_link (tmp, tmp);
+	  text->point.offset = 0;
+
+	  if (GTK_WIDGET_REALIZED (text))
+	    unrealize_property (text, prop);
+
+	  destroy_text_property (prop);
+	  g_list_free_1 (tmp);
+	  
+	  prop = MARK_CURRENT_PROPERTY (&text->point);
+	  
+	  if (is_first)
+	    text->text_properties = MARK_LIST_PTR (&text->point);
+	  
+	  g_assert (prop->length != 0);
+	}
+      else if (prop->length == text->point.offset)
+	{
+	  MARK_LIST_PTR (&text->point) = MARK_NEXT_LIST_PTR (&text->point);
+	  text->point.offset = 0;
+	}
+    }
+  
+  /* Check to see if we have just the single final position remaining
+   * along in a property; if so, combine it with the previous property
+   */
+  if (LAST_INDEX (text, text->point) && 
+      (MARK_OFFSET (&text->point) == 0) &&
+      (MARK_PREV_LIST_PTR(&text->point) != NULL))
+    {
+      tmp = MARK_LIST_PTR (&text->point);
+      prop = MARK_CURRENT_PROPERTY(&text->point);
+      
+      MARK_LIST_PTR (&text->point) = MARK_PREV_LIST_PTR (&text->point);
+      MARK_CURRENT_PROPERTY(&text->point)->length += 1;
+      MARK_NEXT_LIST_PTR(&text->point) = NULL;
+      
+      text->point.offset = MARK_CURRENT_PROPERTY(&text->point)->length - 1;
+      
+      if (GTK_WIDGET_REALIZED (text))
+	unrealize_property (text, prop);
+
+      destroy_text_property (prop);
+      g_list_free_1 (tmp);
+    }
+}
+
+static void
+init_properties (GtkText *text)
+{
+  if (!text->text_properties)
+    {
+      text->text_properties = g_list_alloc();
+      text->text_properties->next = NULL;
+      text->text_properties->prev = NULL;
+      text->text_properties->data = new_text_property (text, NULL, NULL, NULL, 1);
+      text->text_properties_end = text->text_properties;
+      
+      SET_PROPERTY_MARK (&text->point, text->text_properties, 0);
+      
+      text->point.index = 0;
+    }
+}
+
+
+/**********************************************************************/
+/*			   Property Movement                          */
+/**********************************************************************/
+
+static void
+move_mark_n (GtkPropertyMark* mark, gint n)
+{
+  if (n > 0)
+    advance_mark_n(mark, n);
+  else if (n < 0)
+    decrement_mark_n(mark, -n);
+}
+
+static void
+advance_mark (GtkPropertyMark* mark)
+{
+  TextProperty* prop = MARK_CURRENT_PROPERTY (mark);
+  
+  mark->index += 1;
+  
+  if (prop->length > mark->offset + 1)
+    mark->offset += 1;
+  else
+    {
+      mark->property = MARK_NEXT_LIST_PTR (mark);
+      mark->offset   = 0;
+    }
+}
+
+static void
+advance_mark_n (GtkPropertyMark* mark, gint n)
+{
+  gint i;
+  TextProperty* prop;
+
+  g_assert (n > 0);
+
+  i = 0;			/* otherwise it migth not be init. */
+  prop = MARK_CURRENT_PROPERTY(mark);
+
+  if ((prop->length - mark->offset - 1) < n) { /* if we need to change prop. */
+    /* to make it easier */
+    n += (mark->offset);
+    mark->index -= mark->offset;
+    mark->offset = 0;
+    /* first we take seven-mile-leaps to get to the right text
+     * property. */
+    while ((n-i) > prop->length - 1) {
+      i += prop->length;
+      mark->index += prop->length;
+      mark->property = MARK_NEXT_LIST_PTR (mark);
+      prop = MARK_CURRENT_PROPERTY (mark);
+    }
+  }
+
+  /* and then the rest */
+  mark->index += n - i;
+  mark->offset += n - i;
+}
+
+static void
+decrement_mark (GtkPropertyMark* mark)
+{
+  mark->index -= 1;
+  
+  if (mark->offset > 0)
+    mark->offset -= 1;
+  else
+    {
+      mark->property = MARK_PREV_LIST_PTR (mark);
+      mark->offset   = MARK_CURRENT_PROPERTY (mark)->length - 1;
+    }
+}
+
+static void
+decrement_mark_n (GtkPropertyMark* mark, gint n)
+{
+  g_assert (n > 0);
+
+  while (mark->offset < n) {
+    /* jump to end of prev */
+    n -= mark->offset + 1;
+    mark->index -= mark->offset + 1;
+    mark->property = MARK_PREV_LIST_PTR (mark);
+    mark->offset = MARK_CURRENT_PROPERTY (mark)->length - 1;
+  }
+
+  /* and the rest */
+  mark->index -= n;
+  mark->offset -= n;
+}
+ 
+static GtkPropertyMark
+find_mark (GtkText* text, guint mark_position)
+{
+  return find_mark_near (text, mark_position, &text->point);
+}
+
+/*
+ * You can also start from the end, what a drag.
+ */
+static GtkPropertyMark
+find_mark_near (GtkText* text, guint mark_position, const GtkPropertyMark* near)
+{
+  gint diffa;
+  gint diffb;
+  
+  GtkPropertyMark mark;
+  
+  if (!near)
+    diffa = mark_position + 1;
+  else
+    diffa = mark_position - near->index;
+  
+  diffb = mark_position;
+  
+  if (diffa < 0)
+    diffa = -diffa;
+  
+  if (diffa <= diffb)
+    {
+      mark = *near;
+    }
+  else
+    {
+      mark.index = 0;
+      mark.property = text->text_properties;
+      mark.offset = 0;
+    }
+
+  move_mark_n (&mark, mark_position - mark.index);
+   
+  return mark;
+}
+
+/* This routine must be called with scroll == FALSE, only when
+ * point is at least partially on screen
+ */
+
+static void
+find_line_containing_point (GtkText* text, guint point,
+			    gboolean scroll)
+{
+  GList* cache;
+  gint height;
+  
+  text->current_line = NULL;
+
+  TEXT_SHOW (text);
+
+  /* Scroll backwards until the point is on screen
+   */
+  while (CACHE_DATA(text->line_start_cache).start.index > point)
+    scroll_int (text, - LINE_HEIGHT(CACHE_DATA(text->line_start_cache)));
+
+  /* Now additionally try to make sure that the point is fully on screen
+   */
+  if (scroll)
+    {
+      while (text->first_cut_pixels != 0 && 
+	     text->line_start_cache->next &&
+	     CACHE_DATA(text->line_start_cache->next).start.index > point)
+	scroll_int (text, - LINE_HEIGHT(CACHE_DATA(text->line_start_cache->next)));
+    }
+
+  gdk_window_get_size (text->text_area, NULL, &height);
+  
+  for (cache = text->line_start_cache; cache; cache = cache->next)
+    {
+      guint lph;
+      
+      if (CACHE_DATA(cache).end.index >= point ||
+	  LAST_INDEX(text, CACHE_DATA(cache).end))
+	{
+	  text->current_line = cache; /* LOOK HERE, this proc has an
+				       * important side effect. */
+	  return;
+	}
+      
+      TEXT_SHOW_LINE (text, cache, "cache");
+      
+      if (cache->next == NULL)
+	fetch_lines_forward (text, 1);
+      
+      if (scroll)
+	{
+	  lph = pixel_height_of (text, cache->next);
+	  
+	  /* Scroll the bottom of the line is on screen, or until
+	   * the line is the first onscreen line.
+	   */
+	  while (cache->next != text->line_start_cache && lph > height)
+	    {
+	      TEXT_SHOW_LINE (text, cache, "cache");
+	      TEXT_SHOW_LINE (text, cache->next, "cache->next");
+	      scroll_int (text, LINE_HEIGHT(CACHE_DATA(cache->next)));
+	      lph = pixel_height_of (text, cache->next);
+	    }
+	}
+    }
+  
+  g_assert_not_reached (); /* Must set text->current_line here */
+}
+
+static guint
+pixel_height_of (GtkText* text, GList* cache_line)
+{
+  gint pixels = - text->first_cut_pixels;
+  GList *cache = text->line_start_cache;
+  
+  while (TRUE) {
+    pixels += LINE_HEIGHT (CACHE_DATA(cache));
+    
+    if (cache->data == cache_line->data)
+      break;
+    
+    cache = cache->next;
+  }
+  
+  return pixels;
+}
+
+/**********************************************************************/
+/*			Search and Placement                          */
+/**********************************************************************/
+
+static gint
+find_char_width (GtkText* text, const GtkPropertyMark *mark, const TabStopMark *tab_mark)
+{
+  GdkWChar ch;
+  gint16* char_widths;
+  
+  if (LAST_INDEX (text, *mark))
+    return 0;
+  
+  ch = GTK_TEXT_INDEX (text, mark->index);
+  char_widths = MARK_CURRENT_TEXT_FONT (text, mark)->char_widths;
+
+  if (ch == '\t')
+    {
+      return tab_mark->to_next_tab * char_widths[' '];
+    }
+  else if (!text->use_wchar)
+    {
+      return char_widths[ch];
+    }
+  else
+    {
+      return gdk_char_width_wc(MARK_CURRENT_TEXT_FONT(text, mark)->gdk_font, ch);
+    }
+}
+
+static void
+advance_tab_mark (GtkText* text, TabStopMark* tab_mark, GdkWChar ch)
+{
+  if (tab_mark->to_next_tab == 1 || ch == '\t')
+    {
+      if (tab_mark->tab_stops->next)
+	{
+	  tab_mark->tab_stops = tab_mark->tab_stops->next;
+	  tab_mark->to_next_tab = (gulong) tab_mark->tab_stops->data;
+	}
+      else
+	{
+	  tab_mark->to_next_tab = text->default_tab_width;
+	}
+    }
+  else
+    {
+      tab_mark->to_next_tab -= 1;
+    }
+}
+
+static void
+advance_tab_mark_n (GtkText* text, TabStopMark* tab_mark, gint n)
+     /* No tabs! */
+{
+  while (n--)
+    advance_tab_mark (text, tab_mark, 0);
+}
+
+static void
+find_cursor_at_line (GtkText* text, const LineParams* start_line, gint pixel_height)
+{
+  GdkWChar ch;
+  GtkEditable *editable = (GtkEditable *)text;
+  
+  GtkPropertyMark mark        = start_line->start;
+  TabStopMark  tab_mark    = start_line->tab_cont.tab_start;
+  gint         pixel_width = LINE_START_PIXEL (*start_line);
+  
+  while (mark.index < text->cursor_mark.index)
+    {
+      pixel_width += find_char_width (text, &mark, &tab_mark);
+      
+      advance_tab_mark (text, &tab_mark, GTK_TEXT_INDEX(text, mark.index));
+      advance_mark (&mark);
+    }
+  
+  text->cursor_pos_x       = pixel_width;
+  text->cursor_pos_y       = pixel_height;
+  text->cursor_char_offset = start_line->font_descent;
+  text->cursor_mark        = mark;
+  
+  ch = LAST_INDEX (text, mark) ? 
+    LINE_DELIM : GTK_TEXT_INDEX (text, mark.index);
+  
+  if ((text->use_wchar) ? gdk_iswspace (ch) : isspace (ch))
+    text->cursor_char = 0;
+  else
+    text->cursor_char = ch;
+    
+#ifdef USE_XIM
+  if (GTK_WIDGET_HAS_FOCUS(text) && gdk_im_ready() && editable->ic && 
+      (gdk_ic_get_style (editable->ic) & GDK_IM_PREEDIT_POSITION))
+    {
+      GdkICAttributesType mask = GDK_IC_SPOT_LOCATION |
+				 GDK_IC_PREEDIT_FOREGROUND |
+				 GDK_IC_PREEDIT_BACKGROUND;
+
+      editable->ic_attr->spot_location.x = text->cursor_pos_x;
+      editable->ic_attr->spot_location.y
+	= text->cursor_pos_y - text->cursor_char_offset;
+      editable->ic_attr->preedit_foreground = *MARK_CURRENT_FORE (text, &mark);
+      editable->ic_attr->preedit_background = *MARK_CURRENT_BACK (text, &mark);
+
+      if (MARK_CURRENT_FONT (text, &mark)->type == GDK_FONT_FONTSET)
+	{
+	  mask |= GDK_IC_PREEDIT_FONTSET;
+	  editable->ic_attr->preedit_fontset = MARK_CURRENT_FONT (text, &mark);
+	}
+      
+      gdk_ic_set_attr (editable->ic, editable->ic_attr, mask);
+    }
+#endif 
+}
+
+static void
+find_cursor (GtkText* text, gboolean scroll)
+{
+  if (GTK_WIDGET_REALIZED (text))
+    {
+      find_line_containing_point (text, text->cursor_mark.index, scroll);
+      
+      if (text->current_line)
+	find_cursor_at_line (text,
+			     &CACHE_DATA(text->current_line),
+			     pixel_height_of(text, text->current_line));
+    }
+  
+  GTK_EDITABLE (text)->current_pos = text->cursor_mark.index;
+}
+
+static void
+find_mouse_cursor_at_line (GtkText *text, const LineParams* lp,
+			   guint line_pixel_height,
+			   gint button_x)
+{
+  GtkPropertyMark mark     = lp->start;
+  TabStopMark  tab_mark = lp->tab_cont.tab_start;
+  
+  gint char_width = find_char_width(text, &mark, &tab_mark);
+  gint pixel_width = LINE_START_PIXEL (*lp) + (char_width+1)/2;
+  
+  text->cursor_pos_y = line_pixel_height;
+  
+  for (;;)
+    {
+      GdkWChar ch = LAST_INDEX (text, mark) ? 
+	LINE_DELIM : GTK_TEXT_INDEX (text, mark.index);
+      
+      if (button_x < pixel_width || mark.index == lp->end.index)
+	{
+	  text->cursor_pos_x       = pixel_width - (char_width+1)/2;
+	  text->cursor_mark        = mark;
+	  text->cursor_char_offset = lp->font_descent;
+	  
+	  if ((text->use_wchar) ? gdk_iswspace (ch) : isspace (ch))
+	    text->cursor_char = 0;
+	  else
+	    text->cursor_char = ch;
+	  
+	  break;
+	}
+      
+      advance_tab_mark (text, &tab_mark, ch);
+      advance_mark (&mark);
+      
+      pixel_width += char_width/2;
+      
+      char_width = find_char_width (text, &mark, &tab_mark);
+      
+      pixel_width += (char_width+1)/2;
+    }
+}
+
+static void
+find_mouse_cursor (GtkText* text, gint x, gint y)
+{
+  gint pixel_height;
+  GList* cache = text->line_start_cache;
+  
+  g_assert (cache);
+  
+  pixel_height = - text->first_cut_pixels;
+  
+  for (; cache; cache = cache->next)
+    {
+      pixel_height += LINE_HEIGHT(CACHE_DATA(cache));
+      
+      if (y < pixel_height || !cache->next)
+	{
+	  find_mouse_cursor_at_line (text, &CACHE_DATA(cache), pixel_height, x);
+	  
+	  find_cursor (text, FALSE);
+	  
+	  return;
+	}
+    }
+}
+
+/**********************************************************************/
+/*			    Cache Manager                             */
+/**********************************************************************/
+
+static void
+free_cache (GtkText* text)
+{
+  GList* cache = text->line_start_cache;
+  
+  if (cache)
+    {
+      while (cache->prev)
+	cache = cache->prev;
+      
+      text->line_start_cache = cache;
+    }
+  
+  for (; cache; cache = cache->next)
+    g_mem_chunk_free (params_mem_chunk, cache->data);
+  
+  g_list_free (text->line_start_cache);
+  
+  text->line_start_cache = NULL;
+}
+
+static GList*
+remove_cache_line (GtkText* text, GList* member)
+{
+  GList *list;
+  
+  if (member == NULL)
+    return NULL;
+  
+  if (member == text->line_start_cache)
+    text->line_start_cache = text->line_start_cache->next;
+  
+  if (member->prev)
+    member->prev->next = member->next;
+  
+  if (member->next)
+    member->next->prev = member->prev;
+  
+  list = member->next;
+  
+  g_mem_chunk_free (params_mem_chunk, member->data);
+  g_list_free_1 (member);
+  
+  return list;
+}
+
+/**********************************************************************/
+/*			     Key Motion                               */
+/**********************************************************************/
+
+static void
+move_cursor_buffer_ver (GtkText *text, int dir)
+{
+  undraw_cursor (text, FALSE);
+  
+  if (dir > 0)
+    {
+      scroll_int (text, text->vadj->upper);
+      text->cursor_mark = find_this_line_start_mark (text,
+						     TEXT_LENGTH (text),
+						     &text->cursor_mark);
+    }
+  else
+    {
+      scroll_int (text, - text->vadj->value);
+      text->cursor_mark = find_this_line_start_mark (text,
+						     0,
+						     &text->cursor_mark);
+    }
+  
+  find_cursor (text, TRUE);
+  draw_cursor (text, FALSE);
+}
+
+static void
+move_cursor_page_ver (GtkText *text, int dir)
+{
+  scroll_int (text, dir * text->vadj->page_increment);
+}
+
+static void
+move_cursor_ver (GtkText *text, int count)
+{
+  gint i;
+  GtkPropertyMark mark;
+  gint offset;
+  
+  mark = find_this_line_start_mark (text, text->cursor_mark.index, &text->cursor_mark);
+  offset = text->cursor_mark.index - mark.index;
+  
+  if (offset > text->cursor_virtual_x)
+    text->cursor_virtual_x = offset;
+  
+  if (count < 0)
+    {
+      if (mark.index == 0)
+	return;
+      
+      decrement_mark (&mark);
+      mark = find_this_line_start_mark (text, mark.index, &mark);
+    }
+  else
+    {
+      mark = text->cursor_mark;
+      
+      while (!LAST_INDEX(text, mark) && GTK_TEXT_INDEX(text, mark.index) != LINE_DELIM)
+	advance_mark (&mark);
+      
+      if (LAST_INDEX(text, mark))
+	return;
+      
+      advance_mark (&mark);
+    }
+  
+  for (i=0; i < text->cursor_virtual_x; i += 1, advance_mark(&mark))
+    if (LAST_INDEX(text, mark) ||
+	GTK_TEXT_INDEX(text, mark.index) == LINE_DELIM)
+      break;
+  
+  undraw_cursor (text, FALSE);
+  
+  text->cursor_mark = mark;
+  
+  find_cursor (text, TRUE);
+  
+  draw_cursor (text, FALSE);
+}
+
+static void
+move_cursor_hor (GtkText *text, int count)
+{
+  /* count should be +-1. */
+  if ( (count > 0 && text->cursor_mark.index + count > TEXT_LENGTH(text)) ||
+       (count < 0 && text->cursor_mark.index < (- count)) ||
+       (count == 0) )
+    return;
+  
+  text->cursor_virtual_x = 0;
+  
+  undraw_cursor (text, FALSE);
+  
+  move_mark_n (&text->cursor_mark, count);
+  
+  find_cursor (text, TRUE);
+  
+  draw_cursor (text, FALSE);
+}
+
+static void 
+gtk_text_move_cursor (GtkEditable *editable,
+		      gint         x,
+		      gint         y)
+{
+  if (x > 0)
+    {
+      while (x-- != 0)
+	move_cursor_hor (GTK_TEXT (editable), 1);
+    }
+  else if (x < 0)
+    {
+      while (x++ != 0)
+	move_cursor_hor (GTK_TEXT (editable), -1);
+    }
+  
+  if (y > 0)
+    {
+      while (y-- != 0)
+	move_cursor_ver (GTK_TEXT (editable), 1);
+    }
+  else if (y < 0)
+    {
+      while (y++ != 0)
+	move_cursor_ver (GTK_TEXT (editable), -1);
+    }
+}
+
+static void
+gtk_text_move_forward_character (GtkText *text)
+{
+  move_cursor_hor (text, 1);
+}
+
+static void
+gtk_text_move_backward_character (GtkText *text)
+{
+  move_cursor_hor (text, -1);
+}
+
+static void
+gtk_text_move_next_line (GtkText *text)
+{
+  move_cursor_ver (text, 1);
+}
+
+static void
+gtk_text_move_previous_line (GtkText *text)
+{
+  move_cursor_ver (text, -1);
+}
+
+static void 
+gtk_text_move_word (GtkEditable *editable,
+		    gint         n)
+{
+  if (n > 0)
+    {
+      while (n-- != 0)
+	gtk_text_move_forward_word (GTK_TEXT (editable));
+    }
+  else if (n < 0)
+    {
+      while (n++ != 0)
+	gtk_text_move_backward_word (GTK_TEXT (editable));
+    }
+}
+
+static void
+gtk_text_move_forward_word (GtkText *text)
+{
+  text->cursor_virtual_x = 0;
+  
+  undraw_cursor (text, FALSE);
+  
+  if (text->use_wchar)
+    {
+      while (!LAST_INDEX (text, text->cursor_mark) && 
+	     !gdk_iswalnum (GTK_TEXT_INDEX(text, text->cursor_mark.index)))
+	advance_mark (&text->cursor_mark);
+      
+      while (!LAST_INDEX (text, text->cursor_mark) && 
+	     gdk_iswalnum (GTK_TEXT_INDEX(text, text->cursor_mark.index)))
+	advance_mark (&text->cursor_mark);
+    }
+  else
+    {
+      while (!LAST_INDEX (text, text->cursor_mark) && 
+	     !isalnum (GTK_TEXT_INDEX(text, text->cursor_mark.index)))
+	advance_mark (&text->cursor_mark);
+      
+      while (!LAST_INDEX (text, text->cursor_mark) && 
+	     isalnum (GTK_TEXT_INDEX(text, text->cursor_mark.index)))
+	advance_mark (&text->cursor_mark);
+    }
+  
+  find_cursor (text, TRUE);
+  draw_cursor (text, FALSE);
+}
+
+static void
+gtk_text_move_backward_word (GtkText *text)
+{
+  text->cursor_virtual_x = 0;
+  
+  undraw_cursor (text, FALSE);
+  
+  if (text->use_wchar)
+    {
+      while ((text->cursor_mark.index > 0) &&
+	     !gdk_iswalnum (GTK_TEXT_INDEX(text, text->cursor_mark.index-1)))
+	decrement_mark (&text->cursor_mark);
+      
+      while ((text->cursor_mark.index > 0) &&
+	     gdk_iswalnum (GTK_TEXT_INDEX(text, text->cursor_mark.index-1)))
+	decrement_mark (&text->cursor_mark);
+    }
+  else
+    {
+      while ((text->cursor_mark.index > 0) &&
+	     !isalnum (GTK_TEXT_INDEX(text, text->cursor_mark.index-1)))
+	decrement_mark (&text->cursor_mark);
+      
+      while ((text->cursor_mark.index > 0) &&
+	     isalnum (GTK_TEXT_INDEX(text, text->cursor_mark.index-1)))
+	decrement_mark (&text->cursor_mark);
+    }
+  
+  find_cursor (text, TRUE);
+  draw_cursor (text, FALSE);
+}
+
+static void 
+gtk_text_move_page (GtkEditable *editable,
+		    gint         x,
+		    gint         y)
+{
+  if (y != 0)
+    scroll_int (GTK_TEXT (editable), 
+		y * GTK_TEXT(editable)->vadj->page_increment);  
+}
+
+static void 
+gtk_text_move_to_row (GtkEditable *editable,
+		      gint         row)
+{
+}
+
+static void 
+gtk_text_move_to_column (GtkEditable *editable,
+			 gint         column)
+{
+  GtkText *text;
+  
+  text = GTK_TEXT (editable);
+  
+  text->cursor_virtual_x = 0;	/* FIXME */
+  
+  undraw_cursor (text, FALSE);
+  
+  /* Move to the beginning of the line */
+  while ((text->cursor_mark.index > 0) &&
+	 (GTK_TEXT_INDEX (text, text->cursor_mark.index - 1) != LINE_DELIM))
+    decrement_mark (&text->cursor_mark);
+  
+  while (!LAST_INDEX (text, text->cursor_mark) &&
+	 (GTK_TEXT_INDEX (text, text->cursor_mark.index) != LINE_DELIM))
+    {
+      if (column > 0)
+	column--;
+      else if (column == 0)
+	break;
+      
+      advance_mark (&text->cursor_mark);
+    }
+  
+  find_cursor (text, TRUE);
+  draw_cursor (text, FALSE);
+}
+
+static void
+gtk_text_move_beginning_of_line (GtkText *text)
+{
+  gtk_text_move_to_column (GTK_EDITABLE (text), 0);
+  
+}
+
+static void
+gtk_text_move_end_of_line (GtkText *text)
+{
+  gtk_text_move_to_column (GTK_EDITABLE (text), -1);
+}
+
+static void 
+gtk_text_kill_char (GtkEditable *editable,
+		    gint         direction)
+{
+  GtkText *text;
+  
+  text = GTK_TEXT (editable);
+  
+  if (editable->selection_start_pos != editable->selection_end_pos)
+    gtk_editable_delete_selection (editable);
+  else
+    {
+      if (direction >= 0)
+	{
+	  if (text->point.index + 1 <= TEXT_LENGTH (text))
+	    gtk_editable_delete_text (editable, text->point.index, text->point.index + 1);
+	}
+      else
+	{
+	  if (text->point.index > 0)
+	    gtk_editable_delete_text (editable, text->point.index - 1, text->point.index);
+	}
+    }
+}
+
+static void
+gtk_text_delete_forward_character (GtkText *text)
+{
+  gtk_text_kill_char (GTK_EDITABLE (text), 1);
+}
+
+static void
+gtk_text_delete_backward_character (GtkText *text)
+{
+  gtk_text_kill_char (GTK_EDITABLE (text), -1);
+}
+
+static void 
+gtk_text_kill_word (GtkEditable *editable,
+		    gint         direction)
+{
+  if (editable->selection_start_pos != editable->selection_end_pos)
+    gtk_editable_delete_selection (editable);
+  else
+    {
+      gint old_pos = editable->current_pos;
+      if (direction >= 0)
+	{
+	  gtk_text_move_word (editable, 1);
+	  gtk_editable_delete_text (editable, old_pos, editable->current_pos);
+	}
+      else
+	{
+	  gtk_text_move_word (editable, -1);
+	  gtk_editable_delete_text (editable, editable->current_pos, old_pos);
+	}
+    }
+}
+
+static void
+gtk_text_delete_forward_word (GtkText *text)
+{
+  gtk_text_kill_word (GTK_EDITABLE (text), 1);
+}
+
+static void
+gtk_text_delete_backward_word (GtkText *text)
+{
+  gtk_text_kill_word (GTK_EDITABLE (text), -1);
+}
+
+static void 
+gtk_text_kill_line (GtkEditable *editable,
+		    gint         direction)
+{
+  gint old_pos = editable->current_pos;
+  if (direction >= 0)
+    {
+      gtk_text_move_to_column (editable, -1);
+      gtk_editable_delete_text (editable, old_pos, editable->current_pos);
+    }
+  else
+    {
+      gtk_text_move_to_column (editable, 0);
+      gtk_editable_delete_text (editable, editable->current_pos, old_pos);
+    }
+}
+
+static void
+gtk_text_delete_line (GtkText *text)
+{
+  gtk_text_move_to_column (GTK_EDITABLE (text), 0);
+  gtk_text_kill_line (GTK_EDITABLE (text), 1);
+}
+
+static void
+gtk_text_delete_to_line_end (GtkText *text)
+{
+  gtk_text_kill_line (GTK_EDITABLE (text), 1);
+}
+
+static void
+gtk_text_select_word (GtkText *text, guint32 time)
+{
+  gint start_pos;
+  gint end_pos;
+  
+  GtkEditable *editable;
+  editable = GTK_EDITABLE (text);
+  
+  gtk_text_move_backward_word (text);
+  start_pos = text->cursor_mark.index;
+  
+  gtk_text_move_forward_word (text);
+  end_pos = text->cursor_mark.index;
+  
+  editable->has_selection = TRUE;
+  gtk_text_set_selection (editable, start_pos, end_pos);
+  gtk_editable_claim_selection (editable, start_pos != end_pos, time);
+}
+
+static void
+gtk_text_select_line (GtkText *text, guint32 time)
+{
+  gint start_pos;
+  gint end_pos;
+  
+  GtkEditable *editable;
+  editable = GTK_EDITABLE (text);
+  
+  gtk_text_move_beginning_of_line (text);
+  start_pos = text->cursor_mark.index;
+  
+  gtk_text_move_end_of_line (text);
+  gtk_text_move_forward_character (text);
+  end_pos = text->cursor_mark.index;
+  
+  editable->has_selection = TRUE;
+  gtk_text_set_selection (editable, start_pos, end_pos);
+  gtk_editable_claim_selection (editable, start_pos != end_pos, time);
+}
+
+/**********************************************************************/
+/*			      Scrolling                               */
+/**********************************************************************/
+
+static void
+adjust_adj (GtkText* text, GtkAdjustment* adj)
+{
+  gint height;
+  
+  gdk_window_get_size (text->text_area, NULL, &height);
+  
+  adj->step_increment = MIN (adj->upper, (float) SCROLL_PIXELS);
+  adj->page_increment = MIN (adj->upper, height - (float) KEY_SCROLL_PIXELS);
+  adj->page_size      = MIN (adj->upper, height);
+  adj->value          = MIN (adj->value, adj->upper - adj->page_size);
+  adj->value          = MAX (adj->value, 0.0);
+  
+  gtk_signal_emit_by_name (GTK_OBJECT (adj), "changed");
+}
+
+static gint
+set_vertical_scroll_iterator (GtkText* text, LineParams* lp, void* data)
+{
+  SetVerticalScrollData *svdata = (SetVerticalScrollData *) data;
+  
+  if ((text->first_line_start_index >= lp->start.index) &&
+      (text->first_line_start_index <= lp->end.index))
+    {
+      svdata->mark = lp->start;
+  
+      if (text->first_line_start_index == lp->start.index)
+	{
+	  text->first_onscreen_ver_pixel = svdata->pixel_height + text->first_cut_pixels;
+	}
+      else
+	{
+	  text->first_onscreen_ver_pixel = svdata->pixel_height;
+	  text->first_cut_pixels = 0;
+	}
+      
+      text->vadj->value = (float) text->first_onscreen_ver_pixel;
+    }
+  
+  svdata->pixel_height += LINE_HEIGHT (*lp);
+  
+  return FALSE;
+}
+
+static gint
+set_vertical_scroll_find_iterator (GtkText* text, LineParams* lp, void* data)
+{
+  SetVerticalScrollData *svdata = (SetVerticalScrollData *) data;
+  gint return_val;
+  
+  if (svdata->pixel_height <= (gint) text->vadj->value &&
+      svdata->pixel_height + LINE_HEIGHT(*lp) > (gint) text->vadj->value)
+    {
+      svdata->mark = lp->start;
+      
+      text->first_cut_pixels = (gint)text->vadj->value - svdata->pixel_height;
+      text->first_onscreen_ver_pixel = svdata->pixel_height;
+      text->first_line_start_index = lp->start.index;
+      
+      return_val = TRUE;
+    }
+  else
+    {
+      svdata->pixel_height += LINE_HEIGHT (*lp);
+      
+      return_val = FALSE;
+    }
+  
+  return return_val;
+}
+
+static GtkPropertyMark
+set_vertical_scroll (GtkText* text)
+{
+  GtkPropertyMark mark = find_mark (text, 0);
+  SetVerticalScrollData data;
+  gint height;
+  gint orig_value;
+  
+  data.pixel_height = 0;
+  line_params_iterate (text, &mark, NULL, FALSE, &data, set_vertical_scroll_iterator);
+  
+  text->vadj->upper = (float) data.pixel_height;
+  orig_value = (gint) text->vadj->value;
+  
+  gdk_window_get_size (text->text_area, NULL, &height);
+  
+  text->vadj->step_increment = MIN (text->vadj->upper, (float) SCROLL_PIXELS);
+  text->vadj->page_increment = MIN (text->vadj->upper, height - (float) KEY_SCROLL_PIXELS);
+  text->vadj->page_size      = MIN (text->vadj->upper, height);
+  text->vadj->value          = MIN (text->vadj->value, text->vadj->upper - text->vadj->page_size);
+  text->vadj->value          = MAX (text->vadj->value, 0.0);
+  
+  text->last_ver_value = (gint)text->vadj->value;
+  
+  gtk_signal_emit_by_name (GTK_OBJECT (text->vadj), "changed");
+  
+  if (text->vadj->value != orig_value)
+    {
+      /* We got clipped, and don't really know which line to put first. */
+      data.pixel_height = 0;
+      data.last_didnt_wrap = TRUE;
+      
+      line_params_iterate (text, &mark, NULL,
+			   FALSE, &data,
+			   set_vertical_scroll_find_iterator);
+    }
+
+  return data.mark;
+}
+
+static void
+scroll_int (GtkText* text, gint diff)
+{
+  gfloat upper;
+  
+  text->vadj->value += diff;
+  
+  upper = text->vadj->upper - text->vadj->page_size;
+  text->vadj->value = MIN (text->vadj->value, upper);
+  text->vadj->value = MAX (text->vadj->value, 0.0);
+  
+  gtk_signal_emit_by_name (GTK_OBJECT (text->vadj), "value_changed");
+}
+
+static void 
+process_exposes (GtkText *text)
+{
+  GdkEvent *event;
+  
+  /* Make sure graphics expose events are processed before scrolling
+   * again */
+  
+  while ((event = gdk_event_get_graphics_expose (text->text_area)) != NULL)
+    {
+      gtk_widget_event (GTK_WIDGET (text), event);
+      if (event->expose.count == 0)
+	{
+	  gdk_event_free (event);
+	  break;
+	}
+      gdk_event_free (event);
+    }
+}
+
+static gint last_visible_line_height (GtkText* text)
+{
+  GList *cache = text->line_start_cache;
+  gint height;
+  
+  gdk_window_get_size (text->text_area, NULL, &height);
+  
+  for (; cache->next; cache = cache->next)
+    if (pixel_height_of(text, cache->next) > height)
+      break;
+  
+  if (cache)
+    return pixel_height_of(text, cache) - 1;
+  else
+    return 0;
+}
+
+static gint first_visible_line_height (GtkText* text)
+{
+  if (text->first_cut_pixels)
+    return pixel_height_of(text, text->line_start_cache) + 1;
+  else
+    return 1;
+}
+
+static void
+scroll_down (GtkText* text, gint diff0)
+{
+  GdkRectangle rect;
+  gint real_diff = 0;
+  gint width, height;
+  
+  text->first_onscreen_ver_pixel += diff0;
+  
+  while (diff0-- > 0)
+    {
+      if (text->first_cut_pixels < LINE_HEIGHT(CACHE_DATA(text->line_start_cache)) - 1)
+	{
+	  text->first_cut_pixels += 1;
+	}
+      else
+	{
+	  text->first_cut_pixels = 0;
+	  
+	  text->line_start_cache = text->line_start_cache->next;
+	  g_assert (text->line_start_cache);
+      
+	  text->first_line_start_index =
+	    CACHE_DATA(text->line_start_cache).start.index;
+	  
+	  if (!text->line_start_cache->next)
+	    fetch_lines_forward (text, 1);
+	}
+      
+      real_diff += 1;
+    }
+  
+  gdk_window_get_size (text->text_area, &width, &height);
+  if (height > real_diff)
+    gdk_draw_pixmap (text->text_area,
+		     text->gc,
+		     text->text_area,
+		     0,
+		     real_diff,
+		     0,
+		     0,
+		     width,
+		     height - real_diff);
+  
+  rect.x      = 0;
+  rect.y      = MAX (0, height - real_diff);
+  rect.width  = width;
+  rect.height = MIN (height, real_diff);
+  
+  expose_text (text, &rect, FALSE);
+  gtk_text_draw_focus ( (GtkWidget *) text);
+  
+  if (text->current_line)
+    {
+      gint cursor_min;
+      
+      text->cursor_pos_y -= real_diff;
+      cursor_min = drawn_cursor_min(text);
+      
+      if (cursor_min < 0)
+	find_mouse_cursor (text, text->cursor_pos_x,
+			   first_visible_line_height (text));
+    }
+  
+  if (height > real_diff)
+    process_exposes (text);
+}
+
+static void
+scroll_up (GtkText* text, gint diff0)
+{
+  gint real_diff = 0;
+  GdkRectangle rect;
+  gint width, height;
+  
+  text->first_onscreen_ver_pixel += diff0;
+  
+  while (diff0++ < 0)
+    {
+      g_assert (text->line_start_cache);
+      
+      if (text->first_cut_pixels > 0)
+	{
+	  text->first_cut_pixels -= 1;
+	}
+      else
+	{
+	  if (!text->line_start_cache->prev)
+	    fetch_lines_backward (text);
+	  
+	  text->line_start_cache = text->line_start_cache->prev;
+	  
+	  text->first_line_start_index =
+	    CACHE_DATA(text->line_start_cache).start.index;
+	  
+	  text->first_cut_pixels = LINE_HEIGHT(CACHE_DATA(text->line_start_cache)) - 1;
+	}
+      
+      real_diff += 1;
+    }
+  
+  gdk_window_get_size (text->text_area, &width, &height);
+  if (height > real_diff)
+    gdk_draw_pixmap (text->text_area,
+		     text->gc,
+		     text->text_area,
+		     0,
+		     0,
+		     0,
+		     real_diff,
+		     width,
+		     height - real_diff);
+  
+  rect.x      = 0;
+  rect.y      = 0;
+  rect.width  = width;
+  rect.height = MIN (height, real_diff);
+  
+  expose_text (text, &rect, FALSE);
+  gtk_text_draw_focus ( (GtkWidget *) text);
+  
+  if (text->current_line)
+    {
+      gint cursor_max;
+      gint height;
+      
+      text->cursor_pos_y += real_diff;
+      cursor_max = drawn_cursor_max(text);
+      gdk_window_get_size (text->text_area, NULL, &height);
+      
+      if (cursor_max >= height)
+	find_mouse_cursor (text, text->cursor_pos_x,
+			   last_visible_line_height (text));
+    }
+  
+  if (height > real_diff)
+    process_exposes (text);
+}
+
+/**********************************************************************/
+/*			      Display Code                            */
+/**********************************************************************/
+
+/* Assumes mark starts a line.  Calculates the height, width, and
+ * displayable character count of a single DISPLAYABLE line.  That
+ * means that in line-wrap mode, this does may not compute the
+ * properties of an entire line. */
+static LineParams
+find_line_params (GtkText* text,
+		  const GtkPropertyMark* mark,
+		  const PrevTabCont *tab_cont,
+		  PrevTabCont *next_cont)
+{
+  LineParams lp;
+  TabStopMark tab_mark = tab_cont->tab_start;
+  guint max_display_pixels;
+  GdkWChar ch;
+  gint ch_width;
+  GdkFont *font;
+  
+  gdk_window_get_size (text->text_area, (gint*) &max_display_pixels, NULL);
+  if (GTK_EDITABLE (text)->editable || !text->word_wrap)
+    max_display_pixels -= LINE_WRAP_ROOM;
+  
+  lp.wraps             = 0;
+  lp.tab_cont          = *tab_cont;
+  lp.start             = *mark;
+  lp.end               = *mark;
+  lp.pixel_width       = tab_cont->pixel_offset;
+  lp.displayable_chars = 0;
+  lp.font_ascent       = 0;
+  lp.font_descent      = 0;
+  
+  init_tab_cont (text, next_cont);
+  
+  while (!LAST_INDEX(text, lp.end))
+    {
+      g_assert (lp.end.property);
+      
+      ch   = GTK_TEXT_INDEX (text, lp.end.index);
+      font = MARK_CURRENT_FONT (text, &lp.end);
+
+      if (ch == LINE_DELIM)
+	{
+	  /* Newline doesn't count in computation of line height, even
+	   * if its in a bigger font than the rest of the line.  Unless,
+	   * of course, there are no other characters. */
+	  
+	  if (!lp.font_ascent && !lp.font_descent)
+	    {
+	      lp.font_ascent = font->ascent;
+	      lp.font_descent = font->descent;
+	    }
+	  
+	  lp.tab_cont_next = *next_cont;
+	  
+	  return lp;
+	}
+      
+      ch_width = find_char_width (text, &lp.end, &tab_mark);
+      
+      if ((ch_width + lp.pixel_width > max_display_pixels) &&
+	  (lp.end.index > lp.start.index))
+	{
+	  lp.wraps = 1;
+	  
+	  if (text->line_wrap)
+	    {
+	      next_cont->tab_start    = tab_mark;
+	      next_cont->pixel_offset = 0;
+	      
+	      if (ch == '\t')
+		{
+		  /* Here's the tough case, a tab is wrapping. */
+		  gint pixels_avail = max_display_pixels - lp.pixel_width;
+		  gint space_width  = MARK_CURRENT_TEXT_FONT(text, &lp.end)->char_widths[' '];
+		  gint spaces_avail = pixels_avail / space_width;
+		  
+		  if (spaces_avail == 0)
+		    {
+		      decrement_mark (&lp.end);
+		    }
+		  else
+		    {
+		      advance_tab_mark (text, &next_cont->tab_start, '\t');
+		      next_cont->pixel_offset = space_width * (tab_mark.to_next_tab -
+							       spaces_avail);
+		      lp.displayable_chars += 1;
+		    }
+		}
+	      else
+		{
+		  if (text->word_wrap)
+		    {
+		      GtkPropertyMark saved_mark = lp.end;
+		      guint saved_characters = lp.displayable_chars;
+		      
+		      lp.displayable_chars += 1;
+		      
+		      if (text->use_wchar)
+			{
+			  while (!gdk_iswspace (GTK_TEXT_INDEX (text, lp.end.index)) &&
+				 (lp.end.index > lp.start.index))
+			    {
+			      decrement_mark (&lp.end);
+			      lp.displayable_chars -= 1;
+			    }
+			}
+		      else
+			{
+			  while (!isspace(GTK_TEXT_INDEX (text, lp.end.index)) &&
+				 (lp.end.index > lp.start.index))
+			    {
+			      decrement_mark (&lp.end);
+			      lp.displayable_chars -= 1;
+			    }
+			}
+		      
+		      /* If whole line is one word, revert to char wrapping */
+		      if (lp.end.index == lp.start.index)
+			{
+			  lp.end = saved_mark;
+			  lp.displayable_chars = saved_characters;
+			  decrement_mark (&lp.end);
+			}
+		    }
+		  else
+		    {
+		      /* Don't include this character, it will wrap. */
+		      decrement_mark (&lp.end);
+		    }
+		}
+	      
+	      lp.tab_cont_next = *next_cont;
+	      
+	      return lp;
+	    }
+	}
+      else
+	{
+	  lp.displayable_chars += 1;
+	}
+      
+      lp.font_ascent = MAX (font->ascent, lp.font_ascent);
+      lp.font_descent = MAX (font->descent, lp.font_descent);
+      lp.pixel_width  += ch_width;
+      
+      advance_mark(&lp.end);
+      advance_tab_mark (text, &tab_mark, ch);
+    }
+  
+  if (LAST_INDEX(text, lp.start))
+    {
+      /* Special case, empty last line. */
+      font = MARK_CURRENT_FONT (text, &lp.end);
+
+      lp.font_ascent = font->ascent;
+      lp.font_descent = font->descent;
+    }
+  
+  lp.tab_cont_next = *next_cont;
+  
+  return lp;
+}
+
+static void
+expand_scratch_buffer (GtkText* text, guint len)
+{
+  if (len >= text->scratch_buffer_len)
+    {
+      guint i = 1;
+      
+      while (i <= len && i < MIN_GAP_SIZE) i <<= 1;
+      
+      if (text->use_wchar)
+        {
+	  if (!text->scratch_buffer.wc)
+	    text->scratch_buffer.wc = g_new (GdkWChar, i);
+	  else
+	    text->scratch_buffer.wc = g_realloc (text->scratch_buffer.wc,
+						 i * sizeof (GdkWChar));
+        }
+      else
+        {
+	  if (!text->scratch_buffer.ch)
+	    text->scratch_buffer.ch = g_new (guchar, i);
+	  else
+	    text->scratch_buffer.ch = g_realloc (text->scratch_buffer.ch, i);
+        }
+      
+      text->scratch_buffer_len = i;
+    }
+}
+
+/* Side effect: modifies text->gc
+ */
+
+static void
+draw_bg_rect (GtkText* text, GtkPropertyMark *mark,
+	      gint x, gint y, gint width, gint height,
+	      gboolean already_cleared)
+{
+  GtkEditable *editable = GTK_EDITABLE(text);
+
+  if ((mark->index >= MIN(editable->selection_start_pos, editable->selection_end_pos) &&
+       mark->index < MAX(editable->selection_start_pos, editable->selection_end_pos)))
+    {
+      gtk_paint_flat_box(GTK_WIDGET(text)->style, text->text_area,
+			 editable->has_selection ?
+			    GTK_STATE_SELECTED : GTK_STATE_ACTIVE, 
+			 GTK_SHADOW_NONE,
+			 NULL, GTK_WIDGET(text), "text",
+			 x, y, width, height);
+    }
+  else if (!gdk_color_equal(MARK_CURRENT_BACK (text, mark),
+			    &GTK_WIDGET(text)->style->base[GTK_WIDGET_STATE (text)]))
+    {
+      gdk_gc_set_foreground (text->gc, MARK_CURRENT_BACK (text, mark));
+
+      gdk_draw_rectangle (text->text_area,
+			  text->gc,
+			  TRUE, x, y, width, height);
+    }
+  else if (GTK_WIDGET (text)->style->bg_pixmap[GTK_STATE_NORMAL])
+    {
+      GdkRectangle rect;
+      
+      rect.x = x;
+      rect.y = y;
+      rect.width = width;
+      rect.height = height;
+      
+      clear_area (text, &rect);
+    }
+  else if (!already_cleared)
+    gdk_window_clear_area (text->text_area, x, y, width, height);
+}
+
+static void
+draw_line (GtkText* text,
+	   gint pixel_start_height,
+	   LineParams* lp)
+{
+  GdkGCValues gc_values;
+  gint i;
+  gint len = 0;
+  guint running_offset = lp->tab_cont.pixel_offset;
+  union { GdkWChar *wc; guchar *ch; } buffer;
+  GdkGC *fg_gc;
+  
+  GtkEditable *editable = GTK_EDITABLE(text);
+  
+  guint selection_start_pos = MIN (editable->selection_start_pos, editable->selection_end_pos);
+  guint selection_end_pos = MAX (editable->selection_start_pos, editable->selection_end_pos);
+  
+  GtkPropertyMark mark = lp->start;
+  TabStopMark tab_mark = lp->tab_cont.tab_start;
+  gint pixel_height = pixel_start_height + lp->font_ascent;
+  guint chars = lp->displayable_chars;
+  
+  /* First provide a contiguous segment of memory.  This makes reading
+   * the code below *much* easier, and only incurs the cost of copying
+   * when the line being displayed spans the gap. */
+  if (mark.index <= text->gap_position &&
+      mark.index + chars > text->gap_position)
+    {
+      expand_scratch_buffer (text, chars);
+      
+      if (text->use_wchar)
+	{
+	  for (i = 0; i < chars; i += 1)
+	    text->scratch_buffer.wc[i] = GTK_TEXT_INDEX(text, mark.index + i);
+          buffer.wc = text->scratch_buffer.wc;
+	}
+      else
+	{
+	  for (i = 0; i < chars; i += 1)
+	    text->scratch_buffer.ch[i] = GTK_TEXT_INDEX(text, mark.index + i);
+	  buffer.ch = text->scratch_buffer.ch;
+	}
+    }
+  else
+    {
+      if (text->use_wchar)
+	{
+	  if (mark.index >= text->gap_position)
+	    buffer.wc = text->text.wc + mark.index + text->gap_size;
+	  else
+	    buffer.wc = text->text.wc + mark.index;
+	}
+      else
+	{
+	  if (mark.index >= text->gap_position)
+	    buffer.ch = text->text.ch + mark.index + text->gap_size;
+	  else
+	    buffer.ch = text->text.ch + mark.index;
+	}
+    }
+  
+  
+  if (running_offset > 0)
+    {
+      draw_bg_rect (text, &mark, 0, pixel_start_height, running_offset,
+		    LINE_HEIGHT (*lp), TRUE);
+    }
+  
+  while (chars > 0)
+    {
+      len = 0;
+      if ((text->use_wchar && buffer.wc[0] != '\t') ||
+	  (!text->use_wchar && buffer.ch[0] != '\t'))
+	{
+	  union { GdkWChar *wc; guchar *ch; } next_tab;
+	  gint pixel_width;
+	  GdkFont *font;
+
+	  next_tab.wc = NULL;
+	  if (text->use_wchar)
+	    for (i=0; i<chars; i++)
+	      {
+		if (buffer.wc[i] == '\t')
+		  {
+		    next_tab.wc = buffer.wc + i;
+		    break;
+		  }
+	      }
+	  else
+	    next_tab.ch = memchr (buffer.ch, '\t', chars);
+
+	  len = MIN (MARK_CURRENT_PROPERTY (&mark)->length - mark.offset, chars);
+	  
+	  if (text->use_wchar)
+	    {
+	      if (next_tab.wc)
+		len = MIN (len, next_tab.wc - buffer.wc);
+	    }
+	  else
+	    {
+	      if (next_tab.ch)
+		len = MIN (len, next_tab.ch - buffer.ch);
+	    }
+
+	  if (mark.index < selection_start_pos)
+	    len = MIN (len, selection_start_pos - mark.index);
+	  else if (mark.index < selection_end_pos)
+	    len = MIN (len, selection_end_pos - mark.index);
+
+	  font = MARK_CURRENT_FONT (text, &mark);
+	  if (font->type == GDK_FONT_FONT)
+	    {
+	      gdk_gc_set_font (text->gc, font);
+	      gdk_gc_get_values (text->gc, &gc_values);
+	      if (text->use_wchar)
+	        pixel_width = gdk_text_width_wc (gc_values.font,
+						 buffer.wc, len);
+	      else
+		pixel_width = gdk_text_width (gc_values.font,
+					      buffer.ch, len);
+	    }
+	  else
+	    {
+	      if (text->use_wchar)
+		pixel_width = gdk_text_width_wc (font, buffer.wc, len);
+	      else
+		pixel_width = gdk_text_width (font, buffer.ch, len);
+	    }
+	  
+	  draw_bg_rect (text, &mark, running_offset, pixel_start_height,
+			pixel_width, LINE_HEIGHT (*lp), TRUE);
+	  
+	  if ((mark.index >= selection_start_pos) && 
+	      (mark.index < selection_end_pos))
+	    {
+	      if (editable->has_selection)
+		fg_gc = GTK_WIDGET(text)->style->fg_gc[GTK_STATE_SELECTED];
+	      else
+		fg_gc = GTK_WIDGET(text)->style->fg_gc[GTK_STATE_ACTIVE];
+	    }
+	  else
+	    {
+	      gdk_gc_set_foreground (text->gc, MARK_CURRENT_FORE (text, &mark));
+	      fg_gc = text->gc;
+	    }
+
+	  if (text->use_wchar)
+	    gdk_draw_text_wc (text->text_area, MARK_CURRENT_FONT (text, &mark),
+			      fg_gc,
+			      running_offset,
+			      pixel_height,
+			      buffer.wc,
+			      len);
+	  else
+	    gdk_draw_text (text->text_area, MARK_CURRENT_FONT (text, &mark),
+			   fg_gc,
+			   running_offset,
+			   pixel_height,
+			   buffer.ch,
+			   len);
+	  
+	  running_offset += pixel_width;
+	  
+	  advance_tab_mark_n (text, &tab_mark, len);
+	}
+      else
+	{
+	  gint pixels_remaining;
+	  gint space_width;
+	  gint spaces_avail;
+	      
+	  len = 1;
+	  
+	  gdk_window_get_size (text->text_area, &pixels_remaining, NULL);
+	  if (GTK_EDITABLE (text)->editable || !text->word_wrap)
+	    pixels_remaining -= (LINE_WRAP_ROOM + running_offset);
+	  else
+	    pixels_remaining -= running_offset;
+	  
+	  space_width = MARK_CURRENT_TEXT_FONT(text, &mark)->char_widths[' '];
+	  
+	  spaces_avail = pixels_remaining / space_width;
+	  spaces_avail = MIN (spaces_avail, tab_mark.to_next_tab);
+
+	  draw_bg_rect (text, &mark, running_offset, pixel_start_height,
+			spaces_avail * space_width, LINE_HEIGHT (*lp), TRUE);
+
+	  running_offset += tab_mark.to_next_tab *
+	    MARK_CURRENT_TEXT_FONT(text, &mark)->char_widths[' '];
+
+	  advance_tab_mark (text, &tab_mark, '\t');
+	}
+      
+      advance_mark_n (&mark, len);
+      if (text->use_wchar)
+	buffer.wc += len;
+      else
+	buffer.ch += len;
+      chars -= len;
+    }
+}
+
+static void
+draw_line_wrap (GtkText* text, guint height /* baseline height */)
+{
+  gint width;
+  GdkPixmap *bitmap;
+  gint bitmap_width;
+  gint bitmap_height;
+
+  if (!GTK_EDITABLE (text)->editable && text->word_wrap)
+    return;
+  
+  if (text->line_wrap)
+    {
+      bitmap = text->line_wrap_bitmap;
+      bitmap_width = line_wrap_width;
+      bitmap_height = line_wrap_height;
+    }
+  else
+    {
+      bitmap = text->line_arrow_bitmap;
+      bitmap_width = line_arrow_width;
+      bitmap_height = line_arrow_height;
+    }
+  
+  gdk_window_get_size (text->text_area, &width, NULL);
+  width -= LINE_WRAP_ROOM;
+  
+  gdk_gc_set_stipple (text->gc,
+		      bitmap);
+  
+  gdk_gc_set_fill (text->gc, GDK_STIPPLED);
+  
+  gdk_gc_set_foreground (text->gc, &GTK_WIDGET (text)->style->text[GTK_STATE_NORMAL]);
+  
+  gdk_gc_set_ts_origin (text->gc,
+			width + 1,
+			height - bitmap_height - 1);
+  
+  gdk_draw_rectangle (text->text_area,
+		      text->gc,
+		      TRUE,
+		      width + 1,
+		      height - bitmap_height - 1 /* one pixel above the baseline. */,
+		      bitmap_width,
+		      bitmap_height);
+  
+  gdk_gc_set_ts_origin (text->gc, 0, 0);
+  
+  gdk_gc_set_fill (text->gc, GDK_SOLID);
+}
+
+static void
+undraw_cursor (GtkText* text, gint absolute)
+{
+  GtkEditable *editable = (GtkEditable *)text;
+
+  TDEBUG (("in undraw_cursor\n"));
+  
+  if (absolute)
+    text->cursor_drawn_level = 0;
+  
+  if ((text->cursor_drawn_level ++ == 0) &&
+      (editable->selection_start_pos == editable->selection_end_pos) &&
+      GTK_WIDGET_DRAWABLE (text) && text->line_start_cache)
+    {
+      GdkFont* font;
+      
+      g_assert(text->cursor_mark.property);
+
+      font = MARK_CURRENT_FONT(text, &text->cursor_mark);
+
+      draw_bg_rect (text, &text->cursor_mark, 
+		    text->cursor_pos_x,
+		    text->cursor_pos_y - text->cursor_char_offset - font->ascent,
+		    1, font->ascent + 1, FALSE);
+      
+      if (text->cursor_char)
+	{
+	  if (font->type == GDK_FONT_FONT)
+	    gdk_gc_set_font (text->gc, font);
+	  
+	  gdk_gc_set_foreground (text->gc, MARK_CURRENT_FORE (text, &text->cursor_mark));
+	  
+          if (text->use_wchar)
+	    gdk_draw_text_wc (text->text_area, font,
+			      text->gc,
+			      text->cursor_pos_x,
+			      text->cursor_pos_y - text->cursor_char_offset,
+			      &text->cursor_char,
+			      1);
+	  else
+	    {
+	      guchar ch = text->cursor_char;
+	      gdk_draw_text (text->text_area, font,
+			     text->gc,
+			     text->cursor_pos_x,
+			     text->cursor_pos_y - text->cursor_char_offset,
+			     (gchar *)&ch,
+			     1);         
+	    }
+	}
+    }
+}
+
+static gint
+drawn_cursor_min (GtkText* text)
+{
+  GdkFont* font;
+  
+  g_assert(text->cursor_mark.property);
+  
+  font = MARK_CURRENT_FONT(text, &text->cursor_mark);
+  
+  return text->cursor_pos_y - text->cursor_char_offset - font->ascent;
+}
+
+static gint
+drawn_cursor_max (GtkText* text)
+{
+  GdkFont* font;
+  
+  g_assert(text->cursor_mark.property);
+  
+  font = MARK_CURRENT_FONT(text, &text->cursor_mark);
+  
+  return text->cursor_pos_y - text->cursor_char_offset;
+}
+
+static void
+draw_cursor (GtkText* text, gint absolute)
+{
+  GtkEditable *editable = (GtkEditable *)text;
+  
+  TDEBUG (("in draw_cursor\n"));
+  
+  if (absolute)
+    text->cursor_drawn_level = 1;
+  
+  if ((--text->cursor_drawn_level == 0) &&
+      editable->editable &&
+      (editable->selection_start_pos == editable->selection_end_pos) &&
+      GTK_WIDGET_DRAWABLE (text) && text->line_start_cache)
+    {
+      GdkFont* font;
+      
+      g_assert (text->cursor_mark.property);
+
+      font = MARK_CURRENT_FONT (text, &text->cursor_mark);
+
+      gdk_gc_set_foreground (text->gc, &GTK_WIDGET (text)->style->text[GTK_STATE_NORMAL]);
+      
+      gdk_draw_line (text->text_area, text->gc, text->cursor_pos_x,
+		     text->cursor_pos_y - text->cursor_char_offset,
+		     text->cursor_pos_x,
+		     text->cursor_pos_y - text->cursor_char_offset - font->ascent);
+    }
+}
+
+static GdkGC *
+create_bg_gc (GtkText *text)
+{
+  GdkGCValues values;
+  
+  values.tile = GTK_WIDGET (text)->style->bg_pixmap[GTK_STATE_NORMAL];
+  values.fill = GDK_TILED;
+
+  return gdk_gc_new_with_values (text->text_area, &values,
+				 GDK_GC_FILL | GDK_GC_TILE);
+}
+
+static void
+clear_area (GtkText *text, GdkRectangle *area)
+{
+  GtkWidget *widget = GTK_WIDGET (text);
+  
+  if (text->bg_gc)
+    {
+      gint width, height;
+      
+      gdk_window_get_size (widget->style->bg_pixmap[GTK_STATE_NORMAL], &width, &height);
+      
+      gdk_gc_set_ts_origin (text->bg_gc,
+			    (- (gint)text->first_onscreen_hor_pixel) % width,
+			    (- (gint)text->first_onscreen_ver_pixel) % height);
+
+      gdk_draw_rectangle (text->text_area, text->bg_gc, TRUE,
+			  area->x, area->y, area->width, area->height);
+    }
+  else
+    gdk_window_clear_area (text->text_area, area->x, area->y, area->width, area->height);
+}
+
+static void
+expose_text (GtkText* text, GdkRectangle *area, gboolean cursor)
+{
+  GList *cache = text->line_start_cache;
+  gint pixels = - text->first_cut_pixels;
+  gint min_y = MAX (0, area->y);
+  gint max_y = MAX (0, area->y + area->height);
+  gint height;
+  
+  gdk_window_get_size (text->text_area, NULL, &height);
+  max_y = MIN (max_y, height);
+  
+  TDEBUG (("in expose x=%d y=%d w=%d h=%d\n", area->x, area->y, area->width, area->height));
+  
+  clear_area (text, area);
+  
+  for (; pixels < height; cache = cache->next)
+    {
+      if (pixels < max_y && (pixels + (gint)LINE_HEIGHT(CACHE_DATA(cache))) >= min_y)
+	{
+	  draw_line (text, pixels, &CACHE_DATA(cache));
+	  
+	  if (CACHE_DATA(cache).wraps)
+	    draw_line_wrap (text, pixels + CACHE_DATA(cache).font_ascent);
+	}
+      
+      if (cursor && GTK_WIDGET_HAS_FOCUS (text))
+	{
+	  if (CACHE_DATA(cache).start.index <= text->cursor_mark.index &&
+	      CACHE_DATA(cache).end.index >= text->cursor_mark.index)
+	    {
+	      /* We undraw and draw the cursor here to get the drawn
+	       * level right ... FIXME - maybe the second parameter
+	       * of draw_cursor should work differently
+	       */
+	      undraw_cursor (text, FALSE);
+	      draw_cursor (text, FALSE);
+	    }
+	}
+      
+      pixels += LINE_HEIGHT(CACHE_DATA(cache));
+      
+      if (!cache->next)
+	{
+	  fetch_lines_forward (text, 1);
+	  
+	  if (!cache->next)
+	    break;
+	}
+    }
+}
+
+static void 
+gtk_text_update_text    (GtkEditable       *editable,
+			 gint               start_pos,
+			 gint               end_pos)
+{
+  GtkText *text = GTK_TEXT (editable);
+  
+  GList *cache = text->line_start_cache;
+  gint pixels = - text->first_cut_pixels;
+  GdkRectangle area;
+  gint width;
+  gint height;
+  
+  if (end_pos < 0)
+    end_pos = TEXT_LENGTH (text);
+  
+  if (end_pos < start_pos)
+    return;
+  
+  gdk_window_get_size (text->text_area, &width, &height);
+  area.x = 0;
+  area.y = -1;
+  area.width = width;
+  area.height = 0;
+  
+  TDEBUG (("in expose span start=%d stop=%d\n", start_pos, end_pos));
+  
+  for (; pixels < height; cache = cache->next)
+    {
+      if (CACHE_DATA(cache).start.index < end_pos)
+	{
+	  if (CACHE_DATA(cache).end.index >= start_pos)
+	    {
+	      if (area.y < 0)
+		area.y = MAX(0,pixels);
+	      area.height = pixels + LINE_HEIGHT(CACHE_DATA(cache)) - area.y;
+	    }
+	}
+      else
+	break;
+      
+      pixels += LINE_HEIGHT(CACHE_DATA(cache));
+      
+      if (!cache->next)
+	{
+	  fetch_lines_forward (text, 1);
+	  
+	  if (!cache->next)
+	    break;
+	}
+    }
+  
+  if (area.y >= 0)
+    expose_text (text, &area, TRUE);
+}
+
+static void
+recompute_geometry (GtkText* text)
+{
+  GtkPropertyMark mark, start_mark;
+  GList *new_lines;
+  gint height;
+  gint width;
+  
+  free_cache (text);
+  
+  mark = start_mark = set_vertical_scroll (text);
+
+  /* We need a real start of a line when calling fetch_lines().
+   * not the start of a wrapped line.
+   */
+  while (mark.index > 0 &&
+	 GTK_TEXT_INDEX (text, mark.index - 1) != LINE_DELIM)
+    decrement_mark (&mark);
+
+  gdk_window_get_size (text->text_area, &width, &height);
+
+  /* Fetch an entire line, to make sure that we get all the text
+   * we backed over above, in addition to enough text to fill up
+   * the space vertically
+   */
+
+  new_lines = fetch_lines (text,
+			   &mark,
+			   NULL,
+			   FetchLinesCount,
+			   1);
+
+  mark = CACHE_DATA (g_list_last (new_lines)).end;
+  if (!LAST_INDEX (text, mark))
+    {
+      advance_mark (&mark);
+
+      new_lines = g_list_concat (new_lines, 
+				 fetch_lines (text,
+					      &mark,
+					      NULL,
+					      FetchLinesPixels,
+					      height + text->first_cut_pixels));
+    }
+
+  /* Now work forward to the actual first onscreen line */
+
+  while (CACHE_DATA (new_lines).start.index < start_mark.index)
+    new_lines = new_lines->next;
+  
+  text->line_start_cache = new_lines;
+  
+  find_cursor (text, TRUE);
+}
+
+/**********************************************************************/
+/*                            Selection                               */
+/**********************************************************************/
+
+static void 
+gtk_text_set_selection  (GtkEditable   *editable,
+			 gint           start,
+			 gint           end)
+{
+  GtkText *text = GTK_TEXT (editable);
+  
+  guint start1, end1, start2, end2;
+  
+  if (end < 0)
+    end = TEXT_LENGTH (text);
+  
+  start1 = MIN(start,end);
+  end1 = MAX(start,end);
+  start2 = MIN(editable->selection_start_pos, editable->selection_end_pos);
+  end2 = MAX(editable->selection_start_pos, editable->selection_end_pos);
+  
+  if (start2 < start1)
+    {
+      guint tmp;
+      
+      tmp = start1; start1 = start2; start2 = tmp;
+      tmp = end1;   end1   = end2;   end2   = tmp;
+    }
+  
+  undraw_cursor (text, FALSE);
+  editable->selection_start_pos = start;
+  editable->selection_end_pos = end;
+  draw_cursor (text, FALSE);
+  
+  /* Expose only what changed */
+  
+  if (start1 < start2)
+    gtk_text_update_text (editable, start1, MIN(end1, start2));
+  
+  if (end2 > end1)
+    gtk_text_update_text (editable, MAX(end1, start2), end2);
+  else if (end2 < end1)
+    gtk_text_update_text (editable, end2, end1);
+}
+
+
+/**********************************************************************/
+/*                              Debug                                 */
+/**********************************************************************/
+
+#ifdef DEBUG_GTK_TEXT
+static void
+gtk_text_show_cache_line (GtkText *text, GList *cache,
+			  const char* what, const char* func, gint line)
+{
+  LineParams *lp = &CACHE_DATA(cache);
+  gint i;
+  
+  if (cache == text->line_start_cache)
+    g_message ("Line Start Cache: ");
+  
+  if (cache == text->current_line)
+    g_message("Current Line: ");
+  
+  g_message ("%s:%d: cache line %s s=%d,e=%d,lh=%d (",
+	     func,
+	     line,
+	     what,
+	     lp->start.index,
+	     lp->end.index,
+	     LINE_HEIGHT(*lp));
+  
+  for (i = lp->start.index; i < (lp->end.index + lp->wraps); i += 1)
+    g_message ("%c", GTK_TEXT_INDEX (text, i));
+  
+  g_message (")\n");
+}
+
+static void
+gtk_text_show_cache (GtkText *text, const char* func, gint line)
+{
+  GList *l = text->line_start_cache;
+  
+  if (!l) {
+    return;
+  }
+  
+  /* back up to the absolute beginning of the line cache */
+  while (l->prev)
+    l = l->prev;
+  
+  g_message ("*** line cache ***\n");
+  for (; l; l = l->next)
+    gtk_text_show_cache_line (text, l, "all", func, line);
+}
+
+static void
+gtk_text_assert_mark (GtkText         *text,
+		      GtkPropertyMark *mark,
+		      GtkPropertyMark *before,
+		      GtkPropertyMark *after,
+		      const gchar     *msg,
+		      const gchar     *where,
+		      gint             line)
+{
+  GtkPropertyMark correct_mark = find_mark (text, mark->index);
+  
+  if (mark->offset != correct_mark.offset ||
+      mark->property != correct_mark.property)
+    g_warning ("incorrect %s text property marker in %s:%d, index %d -- bad!", where, msg, line, mark->index);
+}
+
+static void
+gtk_text_assert (GtkText         *text,
+		 const gchar     *msg,
+		 gint             line)
+{
+  GList* cache = text->line_start_cache;
+  GtkPropertyMark* before_mark = NULL;
+  GtkPropertyMark* after_mark = NULL;
+  
+  gtk_text_show_props (text, msg, line);
+  
+  for (; cache->prev; cache = cache->prev)
+    /* nothing */;
+  
+  g_message ("*** line markers ***\n");
+  
+  for (; cache; cache = cache->next)
+    {
+      after_mark = &CACHE_DATA(cache).end;
+      gtk_text_assert_mark (text, &CACHE_DATA(cache).start, before_mark, after_mark, msg, "start", line);
+      before_mark = &CACHE_DATA(cache).start;
+      
+      if (cache->next)
+	after_mark = &CACHE_DATA(cache->next).start;
+      else
+	after_mark = NULL;
+      
+      gtk_text_assert_mark (text, &CACHE_DATA(cache).end, before_mark, after_mark, msg, "end", line);
+      before_mark = &CACHE_DATA(cache).end;
+    }
+}
+
+static void
+gtk_text_show_adj (GtkText *text,
+		   GtkAdjustment *adj,
+		   const char* what,
+		   const char* func,
+		   gint line)
+{
+  g_message ("*** adjustment ***\n");
+  
+  g_message ("%s:%d: %s adjustment l=%.1f u=%.1f v=%.1f si=%.1f pi=%.1f ps=%.1f\n",
+	     func,
+	     line,
+	     what,
+	     adj->lower,
+	     adj->upper,
+	     adj->value,
+	     adj->step_increment,
+	     adj->page_increment,
+	     adj->page_size);
+}
+
+static void
+gtk_text_show_props (GtkText *text,
+		     const char* msg,
+		     int line)
+{
+  GList* props = text->text_properties;
+  int proplen = 0;
+  
+  g_message ("%s:%d: ", msg, line);
+  
+  for (; props; props = props->next)
+    {
+      TextProperty *p = (TextProperty*)props->data;
+      
+      proplen += p->length;
+
+      g_message ("[%d,%p,", p->length, p);
+      if (p->flags & PROPERTY_FONT)
+	g_message ("%p,", p->font);
+      else
+	g_message ("-,");
+      if (p->flags & PROPERTY_FOREGROUND)
+	g_message ("%ld, ", p->fore_color.pixel);
+      else
+	g_message ("-,");
+      if (p->flags & PROPERTY_BACKGROUND)
+	g_message ("%ld] ", p->back_color.pixel);
+      else
+	g_message ("-] ");
+    }
+  
+  g_message ("\n");
+  
+  if (proplen - 1 != TEXT_LENGTH(text))
+    g_warning ("incorrect property list length in %s:%d -- bad!", msg, line);
+}
+#endif
diff -ruN gtk+-1.2.10/gtk/gtktypeutils.h gtk-n/gtk/gtktypeutils.h
--- gtk+-1.2.10/gtk/gtktypeutils.h	Fri Aug 18 23:36:34 2000
+++ gtk-n/gtk/gtktypeutils.h	Thu Jan 31 08:55:58 2002
@@ -191,6 +191,13 @@
   GtkTypeClass	*klass;
 };
 
+#ifdef __GNUC__
+struct _GtkTypeClassDummyAlign
+{
+  GtkType type;
+  guint *signals;
+};
+#endif /* __GNUC__ */
 
 /* A GtkTypeClass defines the minimum structure requirements for
  * a types class. Classes returned from gtk_type_class () and
@@ -203,7 +210,11 @@
    *  one unique identifier per class.
    */
   GtkType type;
-};
+}
+#ifdef __GNUC__
+__attribute__ ((aligned (__alignof (struct _GtkTypeClassDummyAlign))))
+#endif /* __GNUC__ */
+;
 
 
 struct _GtkArg
diff -ruN gtk+-1.2.10/gtk/gtkwindow.c gtk-n/gtk/gtkwindow.c
--- gtk+-1.2.10/gtk/gtkwindow.c	Sat Mar 10 00:39:16 2001
+++ gtk-n/gtk/gtkwindow.c	Thu Jan 31 08:57:10 2002
@@ -859,13 +859,60 @@
   GTK_OBJECT_CLASS(parent_class)->finalize (object);
 }
 
+
+static void
+reread_rc_files ()
+{
+  if (gtk_rc_reparse_all ())
+    {
+      /* If the above returned true, some of our RC files are out
+       * of date, so we need to reset all our widgets. Our other
+       * toplevel windows will also get the message, but by
+       * then, the RC file will up to date, so we have to tell
+       * them now.
+       */
+      GList *toplevels;
+      
+      toplevels = gtk_container_get_toplevels();
+      while (toplevels)
+	{
+	  gtk_widget_reset_rc_styles (toplevels->data);
+	  toplevels = toplevels->next;
+	}
+    }
+}
+
 static void
 gtk_window_show (GtkWidget *widget)
 {
   GtkWindow *window = GTK_WINDOW (widget);
   GtkContainer *container = GTK_CONTAINER (window);
   gboolean need_resize;
+  GList *toplevels;
+  gboolean had_visible = FALSE;
+
+  /* If we have no windows shown at this point, then check for
+   * theme changes before showing the window. We really should
+   * be checking realized, not shown, but shown => realized,
+   * and checking in realize might cause reentrancy problems.
+   *
+   * Plus, this allows us to get the new size right before
+   * realizing.
+   */
+  toplevels = gtk_container_get_toplevels ();
+  while (toplevels)
+    {
+      if (GTK_WIDGET_VISIBLE (toplevels->data))
+	{
+	  had_visible = TRUE;
+	  break;
+	}
+      toplevels = toplevels->next;
+    }
 
+  if (!had_visible)
+    reread_rc_files ();
+  
   GTK_WIDGET_SET_FLAGS (widget, GTK_VISIBLE);
 
   need_resize = container->need_resize || !GTK_WIDGET_REALIZED (widget);
@@ -985,7 +1032,13 @@
       break;
     case EnterNotify:
     case LeaveNotify:
-      if (xev->xcrossing.detail != NotifyInferior &&
+      /* We only track the actual destination of keyboard events for real
+       * toplevels, not for embedded toplevels such as GtkPlug. The reason for
+       * this is that GtkPlug redirects events so the widget may effectively not
+       * have the focus even if it actually has the focus.
+       */
+      if (gdk_window_get_parent (GTK_WIDGET (window)->window) == GDK_ROOT_PARENT () &&
+	  xev->xcrossing.detail != NotifyInferior &&
 	  xev->xcrossing.focus && !window->window_has_focus)
 	{
 	  window->window_has_pointer_focus = (xev->xany.type == EnterNotify) ? TRUE : FALSE;
@@ -1474,23 +1527,7 @@
 	}
     }
 
-  if (gtk_rc_reparse_all ())
-    {
-      /* If the above returned true, some of our RC files are out
-       * of date, so we need to reset all our widgets. Our other
-       * toplevel windows will also get the message, but by
-       * then, the RC file will up to date, so we have to tell
-       * them now.
-       */
-      GList *toplevels;
-      
-      toplevels = gtk_container_get_toplevels();
-      while (toplevels)
-	{
-	  gtk_widget_reset_rc_styles (toplevels->data);
-	  toplevels = toplevels->next;
-	}
-    }
+  reread_rc_files ();
 }
 
 static gint
openSUSE Build Service is sponsored by