diff --git a/FL/Fl_Text_Buffer.H b/FL/Fl_Text_Buffer.H
index c23a4a4e794d5940cf584f50f70ae707437b0f6b..d74582deb8a9715639d8f260846dc6797e8121db 100644
--- a/FL/Fl_Text_Buffer.H
+++ b/FL/Fl_Text_Buffer.H
@@ -248,6 +248,18 @@ public:
    */
   unsigned int character(int pos) const;
   
+  /**
+   Convert a byte offset in buffer into a memory address.
+   */
+  const char *address(int pos) const
+  { return (pos < mGapStart) ? mBuf+pos : mBuf+pos+mGapEnd-mGapStart; }
+
+  /**
+   Convert a byte offset in buffer into a memory address.
+   */
+  char *address(int pos)
+  { return (pos < mGapStart) ? mBuf+pos : mBuf+pos+mGapEnd-mGapStart; }
+  
   /** 
    Returns the text from the given rectangle. When you are done
    with the text, free it using the free() function.
@@ -681,6 +693,7 @@ public:
    \return number of byte in substitution
    */
   static int character_width(const char *src, int indent, int tabDist);
+  static int character_width(const char    c, int indent, int tabDist);
 
   /**
    Count the number of displayed characters between buffer position
@@ -934,18 +947,6 @@ protected:
    */
   void update_selections(int pos, int nDeleted, int nInserted);
   
-  /**
-   Convert a byte offset in buffer into a memory address.
-   */
-  const char *address(int pos) const
-  { return (pos < mGapStart) ? mBuf+pos : mBuf+pos+mGapEnd-mGapStart; }
-
-  /**
-   Convert a byte offset in buffer into a memory address.
-   */
-  char *address(int pos)
-  { return (pos < mGapStart) ? mBuf+pos : mBuf+pos+mGapEnd-mGapStart; }
-  
   Fl_Text_Selection mPrimary;     /**< highlighted areas */
   Fl_Text_Selection mSecondary;   /**< highlighted areas */
   Fl_Text_Selection mHighlight;   /**< highlighted areas */
diff --git a/FL/Fl_Text_Display.H b/FL/Fl_Text_Display.H
index 08dc8dad169d3a1d08ea23ca22c83e3c5958b8fe..1268b1bf23980df11e83fbcec9d743858e895ab6 100644
--- a/FL/Fl_Text_Display.H
+++ b/FL/Fl_Text_Display.H
@@ -251,7 +251,7 @@ class FL_EXPORT Fl_Text_Display: public Fl_Group {
                                bool countLastLineMissingNewLine = true) const;
     void find_line_end(int pos, bool start_pos_is_line_start, int *lineEnd,
                          int *nextLineStart) const;
-    int measure_proportional_character(char c, int colNum, int pos) const;
+    int measure_proportional_character(const char *s, int colNum, int pos) const;
     int wrap_uses_character(int lineEndPos) const;
     int range_touches_selection(const Fl_Text_Selection *sel, int rangeStart,
                                  int rangeEnd) const;
diff --git a/src/Fl_Text_Buffer.cxx b/src/Fl_Text_Buffer.cxx
index 5b8341640a7ece4bedf29198d51f2b37025351ed..7ba7a76e611d41dc1308c2c1aa7b399ee7bd7875 100644
--- a/src/Fl_Text_Buffer.cxx
+++ b/src/Fl_Text_Buffer.cxx
@@ -975,6 +975,8 @@ int Fl_Text_Buffer::expand_character(int pos, int indent, char *outStr) const {
 
 // static function and counterpart to "character_width"
 // - unicode ok
+// FIXME: harmonise with new character_width(char*...) version
+//
 int Fl_Text_Buffer::expand_character(const char *src, int indent, char *outStr, int tabDist)
 {
   char c = *src;
@@ -1018,8 +1020,27 @@ int Fl_Text_Buffer::expand_character(const char *src, int indent, char *outStr,
 // - unicode ok
 int Fl_Text_Buffer::character_width(const char *src, int indent, int tabDist)
 {
-  /* Note, this code must parallel that in Fl_Text_Buffer::ExpandCharacter */
   char c = *src;
+  if ((c & 0x80) && (c & 0x40)) {       // first byte of UTF-8 sequence
+    int len = fl_utf8len(c);
+    int ret = 0;
+    unsigned int ucs = fl_utf8decode(src, src+len, &ret);
+    int width = 1; //   mk_wcwidth((wchar_t)ucs); // FIXME
+    // fprintf(stderr, "mk_wcwidth(%x) -> %d (%d, %d, %s)\n", ucs, width, len, ret, s);
+    return width;
+  }
+  if ((c & 0x80) && !(c & 0x40)) {      // other byte of UTF-8 sequence
+    return 0;
+  }
+  return character_width(c, indent, tabDist);
+}
+
+// FIXME: merge the following with the char* version above.
+// but the question then is: how to reorganise expand_character()?
+//
+int Fl_Text_Buffer::character_width(const char    c, int indent, int tabDist)
+{
+  /* Note, this code must parallel that in Fl_Text_Buffer::ExpandCharacter */
   if (c == '\t') {
     return tabDist - (indent % tabDist);
   } else if (((unsigned char) c) <= 31) {
@@ -1032,7 +1053,8 @@ int Fl_Text_Buffer::character_width(const char *src, int indent, int tabDist)
 #endif
     return 1;
   } else if (c & 0x80) {
-    return fl_utf8len(c);
+    // return fl_utf8len(c);
+    return 1;
   }
   return 1;
 }
@@ -1529,8 +1551,7 @@ static void insertColInLine(const char *line, char *insLine, int column,
   const char *linePtr;
   
   for (linePtr = line; *linePtr != '\0'; linePtr++) {
-    len =
-    Fl_Text_Buffer::character_width(linePtr, indent, tabDist);
+    len = Fl_Text_Buffer::character_width(linePtr, indent, tabDist);
     if (indent + len > column)
       break;
     indent += len;
@@ -1573,8 +1594,7 @@ static void insertColInLine(const char *line, char *insLine, int column,
 				   &len);
     for (const char *c = retabbedStr; *c != '\0'; c++) {
       *outPtr++ = *c;
-      len =
-      Fl_Text_Buffer::character_width(c, indent, tabDist);
+      len = Fl_Text_Buffer::character_width(c, indent, tabDist);
       indent += len;
     }
     free((void *) retabbedStr);
@@ -1624,8 +1644,7 @@ static void deleteRectFromLine(const char *line, int rectStart,
   for (c = line; *c != '\0'; c++) {
     if (indent > rectStart)
       break;
-    len =
-    Fl_Text_Buffer::character_width(c, indent, tabDist);
+    len = Fl_Text_Buffer::character_width(c, indent, tabDist);
     if (indent + len > rectStart && (indent == rectStart || *c == '\t'))
       break;
     indent += len;
@@ -1635,8 +1654,7 @@ static void deleteRectFromLine(const char *line, int rectStart,
   
   /* skip the characters between rectStart and rectEnd */
   for (; *c != '\0' && indent < rectEnd; c++)
-    indent +=
-    Fl_Text_Buffer::character_width(c, indent, tabDist);
+    indent += Fl_Text_Buffer::character_width(c, indent, tabDist);
   int postRectIndent = indent;
   
   /* If the line ended before rectEnd, there's nothing more to do */
@@ -1682,8 +1700,7 @@ static void overlayRectInLine(const char *line, char *insLine,
   const char *linePtr = line;
   
   for (; *linePtr != '\0'; linePtr++) {
-    len =
-    Fl_Text_Buffer::character_width(linePtr, inIndent, tabDist);
+    len = Fl_Text_Buffer::character_width(linePtr, inIndent, tabDist);
     if (inIndent + len > rectStart)
       break;
     inIndent += len;
@@ -1709,8 +1726,7 @@ static void overlayRectInLine(const char *line, char *insLine,
   /* skip the characters between rectStart and rectEnd */
   int postRectIndent = rectEnd;
   for (; *linePtr != '\0'; linePtr++) {
-    inIndent +=
-    Fl_Text_Buffer::character_width(linePtr, inIndent, tabDist);
+    inIndent += Fl_Text_Buffer::character_width(linePtr, inIndent, tabDist);
     if (inIndent >= rectEnd) {
       linePtr++;
       postRectIndent = inIndent;
@@ -1738,8 +1754,7 @@ static void overlayRectInLine(const char *line, char *insLine,
     realignTabs(insLine, 0, rectStart, tabDist, useTabs, &len);
     for (const char *c = retabbedStr; *c != '\0'; c++) {
       *outPtr++ = *c;
-      len =
-      Fl_Text_Buffer::character_width(c, outIndent, tabDist);
+      len = Fl_Text_Buffer::character_width(c, outIndent, tabDist);
       outIndent += len;
     }
     free((void *) retabbedStr);
@@ -1895,7 +1910,7 @@ static void addPadding(char *string, int startIndent, int toIndent,
   if (useTabs) {
     while (indent < toIndent) {
       static char t = '\t';
-      len = Fl_Text_Buffer::character_width(&t, indent, tabDist);
+      len = Fl_Text_Buffer::character_width("\t", indent, tabDist);
       if (len > 1 && indent + len <= toIndent) {
 	*outPtr++ = '\t';
 	indent += len;
@@ -2272,6 +2287,7 @@ static char *expandTabs(const char *text, int startIndent, int tabDist, int *new
       indent = startIndent;
       outLen++;
     } else {
+      // FIXME: character_width does not return number of bytes for UTF-8!
       indent +=
       Fl_Text_Buffer::character_width(c, indent, tabDist);
       outLen++;
@@ -2292,6 +2308,7 @@ static char *expandTabs(const char *text, int startIndent, int tabDist, int *new
       indent = startIndent;
       *outPtr++ = *c;
     } else {
+      // FIXME: character_width does not return number of bytes for UTF-8!
       indent +=
       Fl_Text_Buffer::character_width(c, indent, tabDist);
       *outPtr++ = *c;
diff --git a/src/Fl_Text_Display.cxx b/src/Fl_Text_Display.cxx
index 9a6c2eceb9a5f6a82a2a1544d719c61eb35b706b..f086afa86ea6c51ceebc34ab46cf98c3d246473b 100644
--- a/src/Fl_Text_Display.cxx
+++ b/src/Fl_Text_Display.cxx
@@ -644,7 +644,8 @@ void Fl_Text_Display::overstrike(const char* text) {
     ch = buf->character( p );
     if ( ch == '\n' )
       break;
-    indent += Fl_Text_Buffer::character_width( &ch, indent, buf->tab_distance() ); // FIXME: not unicode
+    const char *s = buf->address(p);
+    indent += Fl_Text_Buffer::character_width(s, indent, buf->tab_distance() ); // FIXME: not unicode
     if ( indent == endIndent ) {
       p++;
       break;
@@ -1635,7 +1636,6 @@ void Fl_Text_Display::draw_string( int style, int X, int Y, int toX,
     clear_rect( style, X, Y, toX - X, mMaxsize );
     return;
   }
-
   /* Set font, color, and gc depending on style.  For normal text, GCs
      for normal drawing, or drawing within a Fl_Text_Selection or highlight are
      pre-allocated and pre-configured.  For syntax highlighting, GCs are
@@ -2717,9 +2717,10 @@ void Fl_Text_Display::wrapped_line_counter(Fl_Text_Buffer *buf, int startPos,
     	    colNum = 0;
     	    width = 0;
     	} else {
-          colNum += Fl_Text_Buffer::character_width((char*)&c, colNum, tabDist); // FIXME: unicode
+          const char *s = buf->address(p);
+          colNum += Fl_Text_Buffer::character_width(s, colNum, tabDist); // FIXME: unicode
     	    if (countPixels)
-    	    	width += measure_proportional_character(c, colNum, p+styleBufOffset);
+    	    	width += measure_proportional_character(s, colNum, p+styleBufOffset);
     	}
 
     	/* If character exceeded wrap margin, find the break point
@@ -2737,7 +2738,7 @@ void Fl_Text_Display::wrapped_line_counter(Fl_Text_Buffer *buf, int startPos,
     	    	    	for (i=b+1; i<p+1; i++) {
     	    	    	    width += measure_proportional_character(
                                                                     // FIXME: character is ucs-4
-				    buf->character(i), colNum, 
+				    buf->address(i), colNum, 
 				    i+styleBufOffset);
     	    	    	    colNum++;
     	    	    	}
@@ -2749,9 +2750,10 @@ void Fl_Text_Display::wrapped_line_counter(Fl_Text_Buffer *buf, int startPos,
     	    }
     	    if (!foundBreak) { /* no whitespace, just break at margin */
     	    	newLineStart = max(p, lineStart+1);
-              colNum = Fl_Text_Buffer::character_width((char*)&c, colNum, tabDist); // FIXME: unicode
+              const char *s = buf->address(b);
+              colNum = Fl_Text_Buffer::character_width(s, colNum, tabDist); // FIXME: unicode
     	    	if (countPixels)
-   	    	    width = measure_proportional_character(c, colNum, p+styleBufOffset);
+   	    	    width = measure_proportional_character(s, colNum, p+styleBufOffset);
     	    }
     	    if (p >= maxPos) {
     		*retPos = maxPos;
@@ -2783,9 +2785,9 @@ void Fl_Text_Display::wrapped_line_counter(Fl_Text_Buffer *buf, int startPos,
 }
 
 /**
-   Measure the width in pixels of a character "c" at a particular column
-   "colNum" and buffer position "pos".  This is for measuring characters in
-   proportional or mixed-width highlighting fonts.
+   Measure the width in pixels of the first character of string "s" at a
+   particular column "colNum" and buffer position "pos".  This is for measuring
+   characters in proportional or mixed-width highlighting fonts.
 **
    A note about proportional and mixed-width fonts: the mixed width and
    proportional font code in nedit does not get much use in general editing,
@@ -2796,12 +2798,13 @@ void Fl_Text_Display::wrapped_line_counter(Fl_Text_Buffer *buf, int startPos,
    insertion/deletion, though static display and wrapping and resizing
    should now be solid because they are now used for online help display.
 */
-int Fl_Text_Display::measure_proportional_character(char c, int colNum, int pos) const {
+
+int Fl_Text_Display::measure_proportional_character(const char *s, int colNum, int pos) const {
     int charLen, style;
     char expChar[ FL_TEXT_MAX_EXP_CHAR_LEN ];
     Fl_Text_Buffer *styleBuf = mStyleBuffer;
     
-  charLen = Fl_Text_Buffer::expand_character(&c, colNum, expChar, buffer()->tab_distance()); // FIXME: unicode
+  charLen = Fl_Text_Buffer::expand_character(s, colNum, expChar, buffer()->tab_distance()); // FIXME: unicode
     if (styleBuf == 0) {
 	style = 0;
     } else {