Index: ChangeLog
===================================================================
RCS file: /cvs/gnome/libzvt/ChangeLog,v
retrieving revision 1.350
diff -u -p -r1.350 ChangeLog
--- ChangeLog	10 Sep 2002 06:50:31 -0000	1.350
+++ ChangeLog	13 Nov 2002 21:24:59 -0000
@@ -1,8 +1,254 @@
+Mon Nov 11 12:23:03 2002  HideToshi Tajima  <hidetoshi.tajima@sun.com>
+
+	* libzvt/update.c (vt_draw_selection_part):
+	added l == 0 switch, as line information returned from
+	vt_list_index can be NULL.
+
+Mon Nov  4 19:49:22 2002  HideToshi Tajima  <hidetoshi.tajima@sun.com>
+
+	* libzvt/zvtterm.c (zvt_term_readdata):
+	Fix #96112(2nd): handle EILSEQ error from iconv() - assuming
+	iconv modules should stop conversion at the 1st occurance
+	of the invalid character in conversion input.
+
+Fri Oct 18 17:05:18 2002  HideToshi Tajima  <hidetoshi.tajima@sun.com>
+
+	* libzvt/zvti18n.c (zvt_term_preedit_changed_handler):
+	  Fix #96214: preedit string in libzvt is rendered by pango
+	  layout, but column width of the preedit string was calculated
+	  in monospace way. As the result, when non monospace
+	  font is used, preedit string may not be fully visible.
+
+Thu Oct 17 17:40:18 2002  HideToshi Tajima  <hidetoshi.tajima@sun.com>
+
+	* libzvt/zvtterm.c (zvt_term_readdata):
+	  Fix #96112: properly handle invalid locale character appearances
+	  in read data. They were supposed to be replaced with the number
+	  of '?',  but it did not work well.
+	
+Wed Oct  9 10:39:02 2002  HideToshi Tajima  <hidetoshi.tajima@sun.com>
+
+	* libzvt/zvtterm.c (zvt_term_writechild):
+	convert UTF-8 data to locale's encoding. gnome-terminal always
+	passes UTF-8 data to the terminal widget.
+	(#95230: drag&drop is broken with non-ASCII characters)
+
 2002-09-09  Padraig O'Briain  <padraig.obriain@sun.com>
 
 	* libzvt/zvt-accessible.c (zvt_accessible_draw_text): Call
 	real_draw_text() before zvt_term_get_buffer() so that clearing
 	the screen works correctly. (bug #925653)
+
+Fri Aug 30 15:49:06 2002  HideToshi Tajima  <hidetoshi.tajima@sun.com>
+
+	* libzvt/zvtterm.c (zvt_term_readdata): Patch from RajKumar Sive
+	(#82083)
+	a) Put the IO callback (g_io_add_watch/gdk_input_add) for libzvt 
+	at a lower main loop priority than the GTK main loop - this
+	enables the menu-items to respond faster when a infinite loop like
+	the above one runs.
+	b) For every 8K data read from IO stream zvt_term_readdata()
+	writes it to the viewport (current code blocks till all data come).
+
+	* libzvt/libzvt.h, zvti18n.c, zvtterm.c, vt.c
+	create zvt_term_locale_from_utf8 and zvt_term_locale_to_utf8
+	as g_locale_from_utf8 and g_locale_to_utf8 wrappers and make
+	special case for "C" locale to handle 8-bit characters
+	(#85052)
+
+Mon Aug 19 20:38:17 2002  HideToshi Tajima  <hidetoshi.tajima@sun.com>
+
+	* libzvt/zvti18n.c (zvt_localechar_iswide): given utf8 text should
+	be null-terminated. (work around glib's g_locale_from_utf8 bug
+	(#91222))
+
+Mon Aug 19 14:29:24 2002  HideToshi Tajima  <hidetoshi.tajima@sun.com>
+
+	* libzvt/zvti18n.c (zvt_term_get_xfontset_internal): get font
+	ascent from XFontSet instead of pango metrics(Fixed #90816,
+	#90818).
+
+	* libzvt/zvti18n.c (zvt_term_im_reset): don't reset input method
+	not needed any-time at least in gnome-terminal
+
+Fri Aug 16 09:50:38 2002  HideToshi Tajima  <hidetoshi.tajima@sun.com>
+
+	* libzvt/Makefile.am libzvt/libzvt.h
+	* libzvt/vt.c libzvt/update.c libzvt/zvtterm.c : Move
+	i18n functions to libzvt/zvti18n.c
+	* libzvt/zvti18n.c : new module for i18n functions
+	* libzvt/zterm.c (FONT): use pango font
+
+Thu Aug 15 11:20:31 2002  HideToshi Tajima  <hidetoshi.tajima@sun.com>
+
+	* libzvt/zvtterm.c (zvt_term_preedit_changed_handler):
+	fix some memory trash and leak around feedback attribute list.
+
+Mon Aug 12 20:34:25 2002  HideToshi Tajima  <hidetoshi.tajima@sun.com>
+
+	* libzvt/vt.c: 
+	* libzvt/update.c: 
+	* libzvt/zvtterm.c (localechar_iswide_internal): Fixes #90129
+	
+	use own localechar_iswide function instead of g_unichar_iswide
+	when Xlib drawing functions are used instead of	pango layout.
+
+Thu Aug  8 23:37:29 2002  HideToshi Tajima  <hidetoshi.tajima@sun.com>
+
+	* libzvt/zvtterm.c (zvt_term_readdata): Part of fixes #90129
+	- concat unconverted data to the next read data.
+	- add more error checks.
+	- skip one character and show "?" as a fallback when it's not
+	  able to convert to UTF-8.
+
+	* libzvt/zvtterm.c (paste_received): EUC-JP <-> UTF-8 code
+	converter in libiconv-1.7 does not convert some text like
+	0x8ff3f3 or 0xada1 which kanji command on Solari Ja EUC locale
+	returns, and when they are pasted, a terminal crashes due to
+	conversion error.
+
+Wed Aug  7 16:58:56 2002  HideToshi Tajima  <hidetoshi.tajima@sun.com>
+
+	* libzvt/zvtterm.c: typo ZVT_UTF8 -> ZVT_UTF, this has
+	prevented using "UTF8_STRING" target for the selection
+
+	* libzvt/zvtterm.c:
+	* libzvt/update.h:
+	* libzvt/vt.c:
+	* libzvt/libzvt.h:
+	* libzvt/vt.h:	merge changes from HEAD
+	
+Wed Aug  7 15:27:24 2002  HideToshi Tajima  <hidetoshi.tajima@sun.com>
+
+	* libzvt/zvtterm.c (zvt_term_real_copy_clipboard): set type
+	of the selection data to one for UTF-32 so that it should be
+	converted to UTF-8 at zvt_term_convert_selection.
+
+	* libzvt/zvtterm.c (zvt_term_convert_selection):
+	g_warning if UTF-32 text is requested.
+	
+Wed Aug  7 13:45:21 2002  HideToshi Tajima  <hidetoshi.tajima@sun.com>
+
+	* libzvt/zvtterm.c (zvt_term_init): 
+	* libzvt/zvtterm.c (zvt_term_set_pango_font):
+	manage properly zp->pango_font, zp->pango_font_bold, for memory
+	initiation, allocation and free.
+
+Wed Aug  7 12:59:28 2002  HideToshi Tajima  <hidetoshi.tajima@sun.com>
+
+	* libzvt/zvtterm.c (zvt_term_destroy): comment out code to
+	free pango font description upon closing a window or a tab.
+	This would make a terminal crash in CJK locales where preedit
+	text is drawn with pango layout function.
+
+Wed Aug  7 09:57:16 2002  HideToshi Tajima  <hidetoshi.tajima@sun.com>
+
+	* libzvt/zvtterm.c (zvt_term_cursor_blink): restore
+	the comment out of this function - this was done so while
+	debugging..
+
+Tue Aug  6 16:35:30 2002  HideToshi Tajima  <hidetoshi.tajima@sun.com>
+
+	* libzvt/zvtterm.c (vt_draw_text): filling makes weired stripe
+	output when background effect(background image or transparent
+	background) is used
+
+Tue Aug  6 15:46:56 2002  HideToshi Tajima  <hidetoshi.tajima@sun.com>
+
+	* libzvt/zvtterm.c (vt_draw_text): revert one change to create
+	own XGC to fill spacing
+
+Tue Aug  6 15:25:13 2002  HideToshi Tajima  <hidetoshi.tajima@sun.com>
+
+	* libzvt/zvtterm.c (zvt_term_readdata):
+	- use g_locale_to_utf8 instead of g_convert_with_fallback
+	- fixed memory leak
+	* libzvt/zvtterm.c (vt_draw_text):
+	- No need to create own XGC to fill spacing
+	
+Mon Aug  5 16:27:15 2002  HideToshi Tajima  <hidetoshi.tajima@sun.com>
+
+	* libzvt/zvtterm.c (zvt_term_get_xfontset_internal):
+	- get maximam per character width and height of ASCII characters.
+	- should not use new fontset when either of charwidth or
+	charheight with the new fontset is 0.
+
+Sat Aug  3 11:31:51 2002  HideToshi Tajima  <hidetoshi.tajima@sun.com>
+
+	* libzvt/zvtterm.c (zvt_term_get_xfontset): 
+	- add a few more fallback methods to create a XFontSet
+	- free missing charset list
+	
+	* libzvt/zvtterm.c (vt_draw_text):
+	set foreground properly - this should fix ru.koi8-r weired
+	"filling" problem pointed by Pablo.
+	
+Fri Aug  2 18:52:35 2002  HideToshi Tajima  <hidetoshi.tajima@sun.com>
+
+	* libzvt/zvtterm.c (zvt_term_set_pango_font):
+	avoid recursive call of zvt_term_set_font_name - which would cause
+	infinite loop when fontset creation fails.
+
+Fri Aug  2 17:47:02 2002  HideToshi Tajima  <hidetoshi.tajima@sun.com>
+
+	* libzvt/zvtterm.c (zvt_term_get_xfontset):
+	get the approxiamate text width and height of whole ASCII
+	characters and use it for per-char width and height.
+
+Fri Aug  2 14:13:27 2002  HideToshi Tajima  <hidetoshi.tajima@sun.com>
+
+	* libzvt/zvtterm.c (xlfd_from_pango_font_description):
+	check #if XlibSpecificationRelease >= 6 for XOpenOM/XGetOMValues,
+	which were not in X11R5.
+	
+Fri Aug  2 13:52:43 2002  HideToshi Tajima  <hidetoshi.tajima@sun.com>
+
+	* libzvt/zvtterm.c (xlfd_from_pango_font_description):
+	get required charsets for the locale from XOpenOM first, then
+	try default encodings, based on an idea from Pablo Saratxaga
+	<pablo@mandrakesoft.com.>
+
+Thu Aug  1 21:05:06 2002  HideToshi Tajima  <hidetoshi.tajima@sun.com>
+
+	* libzvt/zvtterm.c (vt_draw_text): 
+	spacing between chars can be less than 0, there is no filling
+	needed in this case.
+
+Thu Aug  1 18:50:33 2002  HideToshi Tajima  <hidetoshi.tajima@sun.com>
+
+	* libzvt/Makefile.am, libzvt/zvtterm.c, libzvt/libzvt.h,
+	  libzvt/update.c, libzvt/vt.c, libzvt/vt.h
+	
+	    lots of updates (Special thanks to Nalin and Havoc:-)
+	
+	    - #ifdef SUN_I18N -> #ifdef HAS_I18N
+	    - use Xlib's XmbDrawString and XmbDrawImageString directly
+	      instead of PangoLayout when drawing text on terminal widget
+	      mainly for performance's sake.
+	    - draw one character at a time to handle non-monospaced fonts
+	    - use VTE's code to get XLFD fontnames from PangoFontDescription
+	
+Wed Jul 31 10:00:40 2002  HideToshi Tajima  <hidetoshi.tajima@sun.com>
+
+	* libzvt/zvtterm.c (vt_cursor_state):
+	set cursor location to the input methods.
+
+Mon Jul 29 14:13:19 2002  HideToshi Tajima  <hidetoshi.tajima@sun.com>
+
+	* libzvt/libzvt.h: add zvt_term_set_pango_font () so that
+	gnome-terminal can use pango fonts instead of x fonts in its
+	profile.
+
+Fri Jul 19 11:37:01 2002  HideToshi Tajima  <hidetoshi.tajima@sun.com>
+
+	* libzvt/zvtterm.c (vt_draw_text): Always needs to set 
+	PangoLanguage after getting Pango Context.
+
+Tue Jul  9 13:06:22 2002  HideToshi Tajima  <hidetoshi.tajima@sun.com>
+
+	* libzvt/zvtterm.c (zvt_term_preedit_changed_handler): scrolling
+	preedit	window
+	* libzvt/vt.c (vt_parse_vt): linewrapping wide char.
 
 2002-06-24  jacob berkman  <jacob@ximian.com>
 
Index: libzvt/Makefile.am
===================================================================
RCS file: /cvs/gnome/libzvt/libzvt/Makefile.am,v
retrieving revision 1.63
diff -u -p -r1.63 Makefile.am
--- libzvt/Makefile.am	24 Jun 2002 15:15:59 -0000	1.63
+++ libzvt/Makefile.am	13 Nov 2002 21:25:01 -0000
@@ -22,7 +22,8 @@ INCLUDES = \
 	-DG_DISABLE_DEPRECATED		\
 	-DGDK_DISABLE_DEPRECATED	\
 	-DGDK_PIXBUF_DISABLE_DEPRECATED \
-	-DGTK_DISABLE_DEPRECATED
+	-DGTK_DISABLE_DEPRECATED	\
+	-DHAS_I18N
 
 libzvt_2_includedir = $(includedir)/libzvt-2.0/libzvt
 
@@ -46,6 +47,7 @@ libzvt_2_0_la_SOURCES = \
 	background.c		\
 	background.h		\
 	zvtterm.c		\
+	zvti18n.c		\
 	zvt-marshal.c		\
 	zvt-marshal.h		\
 	zvt-accessible.c	\
Index: libzvt/libzvt.h
===================================================================
RCS file: /cvs/gnome/libzvt/libzvt/libzvt.h,v
retrieving revision 1.15
diff -u -p -r1.15 libzvt.h
--- libzvt/libzvt.h	3 Jun 2002 16:59:26 -0000	1.15
+++ libzvt/libzvt.h	13 Nov 2002 21:25:01 -0000
@@ -17,6 +17,28 @@
  *  License along with this program; if not, write to the Free Software
  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
+/*
+  I18N codes are added by
+	Naoyuki Ishimura <naoyuki.ishimura@sun.com>
+	Hidetoshi Tajima <hidetoshi.tajima@sun.com>
+
+   Copyright (C) 2002 Sun Microsystems, Inc.
+
+   The Gnome 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.
+
+   The Gnome 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 the Gnome Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.
+*/
 #ifndef LIBZVT_H
 #define LIBZVT_H
 
@@ -37,6 +59,10 @@ END_GNOME_DECLS
 #include <gtk/gtkadjustment.h>
 #include <gtk/gtkwidget.h>
 #include <gtk/gtksignal.h>
+#ifdef HAS_I18N
+#include <X11/Xlib.h>
+#include <gtk/gtkimcontext.h>
+#endif
 #include <libzvt/vtx.h>
 #include <libzvt/background.h>
 
@@ -121,6 +147,14 @@ struct _ZvtTerm
   GdkColor colors [18];		/* GdkColor for colormap support */
   /* GdkIC depecated, needto be substituted with GtkIMContext, not yet done */
   /* GdkIC *ic;*/		/* input context */
+#ifdef HAS_I18N
+  /* input context */
+  GtkIMContext *ic;
+  gboolean need_im_reset;
+  XFontSet xfontset;
+  int font_ascent;
+  int padding;
+#endif  
 
  /* file name of a pixmap, if NULL, none is loaded
   * and normal mode is used
@@ -210,6 +244,13 @@ struct _zvtprivate
   unsigned short *queue_red, *queue_green, *queue_blue;
 
   char auto_hint;		/* when 1, we automatically set window manager size hints */
+
+#ifdef HAS_I18N
+  PangoContext *pango_context;
+  PangoFontDescription *pango_font;
+  PangoFontDescription *pango_font_bold;
+  GdkWindow *preedit_window;
+#endif /* HAS_I18N */  
 };
 
 /* *** DO NOT USE THIS IN APPS! *** */
@@ -240,6 +281,43 @@ char        *zvt_term_get_buffer	       
 						int type,
 						int sx, int sy,
 						int ex, int ey);
+#ifdef HAS_I18N
+gchar*	     zvt_term_locale_from_utf8		(const gchar *utf8_ptr,
+						 const gssize utf8_len,
+						 gsize *bytes_read,
+						 gsize *bytes_written,
+						 GError **error);
+
+gchar*	     zvt_term_locale_to_utf8		(const gchar *locale_ptr,
+						 const gssize locale_len,
+						 gsize *bytes_read,
+						 gsize *bytes_written,
+						 GError **error);
+
+void         zvt_term_set_pango_font            (ZvtTerm *term,
+						 const PangoFontDescription*);
+gboolean     zvt_localechar_iswide		(gunichar);
+gint	     zvt_column_from_utf8		(gchar *, gint);
+
+void	     zvt_term_im_new			(ZvtTerm *term);
+void	     zvt_term_im_cursor_location	(ZvtTerm *term);
+void	     zvt_term_preedit_update		(ZvtTerm *term);
+void	     zvt_term_im_reset			(ZvtTerm *term);
+void	     zvt_term_im_free			(ZvtTerm *term);
+
+void	     zvt_term_get_baseline_offset	(ZvtTerm *term,
+						 int row, int col,
+						 gint *offset_x, gint *offset_y);
+void	     zvt_term_draw_text			(ZvtTerm *term,
+						 struct vt_line *line,
+						 int row, int col,
+						 gchar *utf8_ptr, int len,
+						 int x, int y,
+						 int offx, int offy,
+						 GdkGC *fgc,
+						 int dofill, int overstrike);
+#endif
+void	     zvt_term_scroll		       (ZvtTerm *term, int n);
 void         zvt_term_set_font_name            (ZvtTerm *term, char *name);
 void         zvt_term_set_fonts                (ZvtTerm *term,
 						GdkFont *font,
Index: libzvt/update.c
===================================================================
RCS file: /cvs/gnome/libzvt/libzvt/update.c,v
retrieving revision 1.72
diff -u -p -r1.72 update.c
--- libzvt/update.c	11 Jun 2002 16:04:32 -0000	1.72
+++ libzvt/update.c	13 Nov 2002 21:25:01 -0000
@@ -17,6 +17,28 @@
  *  License along with this program; if not, write to the Free Software
  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
+/*
+  I18N codes are added by
+	Naoyuki Ishimura <naoyuki.ishimura@sun.com>
+	Hidetoshi Tajima <hidetoshi.tajima@sun.com>
+
+   Copyright (C) 2002 Sun Microsystems, Inc.
+
+   The Gnome 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.
+
+   The Gnome 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 the Gnome Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.
+*/
 
 /*
   This module handles the update of the 'on-screen' virtual terminal
@@ -150,10 +172,20 @@ static void vt_line_update(struct _vtx *
     /* used in both if cases */
     newattr = newchar & VTATTR_MASK;
 
+#ifdef HAS_I18N
+    if (newchar & VTATTR_UTF16_HALF) {
+      newattr &= ~VTATTR_UTF16_HALF;
+    }
+#endif
     /* if there are no changes, quit right here ... */
     if (oldchar != newchar || force) {
       bl->data[i] = newchar;
       oldattr = oldchar & VTATTR_MASK;
+#ifdef HAS_I18N
+      if (oldchar & VTATTR_UTF16_HALF) {
+	oldattr &= ~VTATTR_UTF16_HALF;
+      }
+#endif      
       if (run) {
 	if (newattr == attr) {
 	  if (vx->back_match) {
@@ -1002,6 +1034,71 @@ static char *vt_expand_line(struct vt_li
   if (start<0)
     start=0;
  
+#ifdef HAS_I18N
+  switch (size) {
+  case 4:
+    {
+      gunichar uc;
+      gunichar *ucs4_ptr = (gunichar *)out;
+      for (i = start; i < end; i++) {
+	uc = 0;
+	if (l->data[i] & VTATTR_UTF16_HALF) {
+	  uc = (l->data[i++] & VTATTR_DATAMASK) << 16;
+	}
+	uc |= l->data[i] & VTATTR_DATAMASK;
+	if (state == 0) {
+	  if (uc == 0x09)
+	    state = 1;
+	  else if (uc < 32)
+	    uc = ' ';
+	  *ucs4_ptr++ = uc; 
+	} else {
+	  if (uc) {
+	    if (uc != 0x09)
+	      state = 0;
+	    *ucs4_ptr++ = uc;
+	  }
+	}
+      }
+      if (lf)
+	*ucs4_ptr++ = '\n';
+      out = (char *)ucs4_ptr; 
+    }
+    break;
+  default:
+    {
+      /* convert to UTF-8 */
+      gunichar uc;
+      gchar *utf8_ptr = out;
+      gint utf8_len;
+      for (i = start; i < end; i++) {
+	uc = 0;
+	if (l->data[i] & VTATTR_UTF16_HALF) {
+	  uc = (l->data[i++] & VTATTR_DATAMASK) << 16;
+	}
+	uc |= l->data[i] & VTATTR_DATAMASK;
+	if (state == 0) {
+	  if (uc == 0x09)
+	    state = 1;
+	  else if (uc < 32)
+	    uc = ' ';
+	  utf8_ptr += g_unichar_to_utf8(uc, utf8_ptr);
+	} else {
+	  if (uc) {
+	    if (uc != 0x09)
+	      state = 0;
+	    utf8_ptr += g_unichar_to_utf8(uc, utf8_ptr);
+	  }
+	}
+      }
+      if (lf)
+	*utf8_ptr++ = '\n';
+      out = utf8_ptr;
+    }
+  }
+#endif
+
+#ifdef YUCK
   /* YUCK!  oh well, this seems easiest way to do this! */
   switch(size) {
   case 2: {
@@ -1082,6 +1179,7 @@ static char *vt_expand_line(struct vt_li
   }
   break;
   }
+#endif /* YUCK */
   return out;
 }
 
@@ -1159,8 +1257,16 @@ vt_select_block(struct _vtx *vx, int siz
       out = vt_expand_line(wn, size, 0, ex, out);
   }
 
+#ifdef HAS_I18N
+  *out = 0;
+  if (size == 1) 
+    *len = zvt_column_from_utf8 (data, strlen(data));
+  else
+    *len = (out - data) / size;
+#else  
   *len = (out-data)/size;
   *out = 0;
+#endif /* HAS_I18N */
 
   d(printf("selected text = \n");
     fwrite(data, out-data, 1, stdout);
@@ -1221,6 +1327,9 @@ static void vt_draw_selection_part(struc
   } else {
     l = (struct vt_line *)vt_list_index(&vx->vt.lines, line);
   }
+
+  if (l == 0)
+    return;
 
   if ((line-vx->vt.scrollbackoffset)>=0)
     bl = (struct vt_line *)vt_list_index(&vx->vt.lines_back, line-vx->vt.scrollbackoffset);
Index: libzvt/vt.c
===================================================================
RCS file: /cvs/gnome/libzvt/libzvt/vt.c,v
retrieving revision 1.87
diff -u -p -r1.87 vt.c
--- libzvt/vt.c	3 Jun 2002 16:59:26 -0000	1.87
+++ libzvt/vt.c	13 Nov 2002 21:25:01 -0000
@@ -19,6 +19,28 @@
  */
 
 /*
+  I18N codes are added by
+	Naoyuki Ishimura <naoyuki.ishimura@sun.com>
+	Hidetoshi Tajima <hidetoshi.tajima@sun.com>
+
+   Copyright (C) 2002 Sun Microsystems, Inc.
+
+   The Gnome 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.
+
+   The Gnome 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 the Gnome Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.
+*/
+/*
   This module handles the update of the 'off-screen' virtual terminal
 */
 
@@ -634,7 +656,11 @@ static void vt_tab(struct vt_em *vt)
   c = l->data[vt->cursorx] & VTATTR_DATAMASK;
 
   /* dont store tab over a space - will affect attributes */
+#ifdef HAS_I18N
+  if (c == 0 && !(l->data[vt->cursorx] & VTATTR_UTF16_HALF)) {
+#else    
   if (c == 0) {
+#endif    
     /* We do not store the attribute as tabs are transparent
      * with respect to attributes
      */
@@ -1408,7 +1434,7 @@ vt_set_text(struct vt_em *vt)
         }
       else
         {
-          utf8 = g_locale_to_utf8 (p, -1, NULL, NULL, NULL);
+          utf8 = zvt_term_locale_to_utf8 (p, -1, NULL, NULL, NULL);
           /* utf8 will be NULL if the title was not valid
            * in the locale encoding
            */
@@ -1494,6 +1520,15 @@ vt_parse_vt (struct vt_em *vt, char *ptr
   struct vt_jump *modes = vtjumps;
   char *ptr_end;
   void (*process)(struct vt_em *vt);	/* process function */
+#ifdef HAS_I18N
+  /* convert UTF8 to UCS4 and process only 7 bit code
+   * must free ucs4 at the end of this function
+   */
+  glong i;
+  glong char_length;
+  gboolean iswide;
+  gunichar *ucs4 = g_utf8_to_ucs4_fast (ptr, length, &char_length);
+#endif /* HAS_I18N */
 
   /* states:
    *   0: normal escape mode
@@ -1512,6 +1547,12 @@ vt_parse_vt (struct vt_em *vt, char *ptr
    */
 
   state = vt->state;
+#ifdef HAS_I18N
+  for (i = 0; i < char_length; i++) {
+    c = ucs4[i];
+#endif
+
+#ifdef YUCK  
   ptr_end = ptr + length;
   while (ptr < ptr_end) {
 
@@ -1559,7 +1600,18 @@ vt_parse_vt (struct vt_em *vt, char *ptr
     mode = modes[c & 0x7f].modes;
     process = modes[c & 0x7f].process;
 #endif /* ZVT_UTF */
+#endif /* YUCK */
 
+#ifdef HAS_I18N
+    if (c <= 0x7f) {
+      mode = modes[c].modes;
+      process = modes[c].process;
+    } else {
+      mode = VT_LIT;
+      process = 0;
+    }
+#endif /* HAS_I18N */    
+	
     vt->state = state;		/* so callbacks know their state */
     
     d(printf("state %d: %d $%02x '%c'\n",state, vt->argcnt, c, isprint(c)?c:'.'));
@@ -1574,10 +1626,20 @@ vt_parse_vt (struct vt_em *vt, char *ptr
 	
 	/* insert mode? */
 	if (vt->mode & VTMODE_INSERT)
+#ifdef HAS_I18N
+	  if (zvt_localechar_iswide(c)) {
+	    vt_insert_chars(vt, 2);
+	  } else
+#endif	    
 	  vt_insert_chars(vt, 1);
 	
 	/* need to wrap? */
+#ifdef HAS_I18N
+	iswide = zvt_localechar_iswide(c);
+	if (vt->cursorx >= vt->width - (iswide ? 1 : 0)) {
+#else	  
 	if (vt->cursorx>=vt->width) {
+#endif	  
 	  if (vt->mode&VTMODE_WRAPOFF)
 	    vt->cursorx = vt->width-1;
 	  else {
@@ -1587,7 +1649,20 @@ vt_parse_vt (struct vt_em *vt, char *ptr
 	}
 	
 	/* output character */
+#ifdef HAS_I18N
+	if (iswide) {
+	  /* - this will be zero data other than UTF16 surrogate pair character
+	   * - put this to data as these characters occupy two columns   
+	   */
+	  vt->this_line->data[vt->cursorx] =
+	    ((vt->attr) & VTATTR_MASK) | VTATTR_UTF16_HALF | ((c & 0xffff0000) >> 16);
+	  vt->this_line->modcount++;
+	  vt->cursorx++;
+	}
+	vt->this_line->data[vt->cursorx] = ((vt->attr) & VTATTR_MASK) | (VTATTR_DATAMASK & c); 
+#else
 	vt->this_line->data[vt->cursorx] = ((vt->attr) & VTATTR_MASK) | c;
+#endif /* HAS_I18N */
 	vt->this_line->modcount++;
 	/* d(printf("literal %c\n", c)); */
 	vt->cursorx++;
@@ -1706,6 +1781,10 @@ vt_parse_vt (struct vt_em *vt, char *ptr
   }
 
   vt->state = state;
+
+#ifdef HAS_I18N
+  g_free (ucs4);
+#endif  
 }
 
 /**
Index: libzvt/vt.h
===================================================================
RCS file: /cvs/gnome/libzvt/libzvt/vt.h,v
retrieving revision 1.31
diff -u -p -r1.31 vt.h
--- libzvt/vt.h	29 Nov 2001 23:56:28 -0000	1.31
+++ libzvt/vt.h	13 Nov 2002 21:25:01 -0000
@@ -18,6 +18,29 @@
  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+/*
+  I18N codes are added by
+	Naoyuki Ishimura <naoyuki.ishimura@sun.com>
+	Hidetoshi Tajima <hidetoshi.tajima@sun.com>
+
+   Copyright (C) 2002 Sun Microsystems, Inc.
+
+   The Gnome 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.
+
+   The Gnome 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 the Gnome Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.
+*/
+
 #ifndef _ZVT_VT_H_
 #define _ZVT_VT_H_
 
@@ -72,6 +95,9 @@ typedef enum {
 #define VTATTR_BLINK      0x10000000
 #define VTATTR_REVERSE    0x08000000
 #define VTATTR_CONCEALED  0x04000000
+#ifdef HAS_I18N
+#define VTATTR_UTF16_HALF 0x80000000
+#endif
 
 /* all attributes mask, and no-attributes mask */
 #define VTATTR_MASK	  0xffff0000
Index: libzvt/zterm.c
===================================================================
RCS file: /cvs/gnome/libzvt/libzvt/zterm.c,v
retrieving revision 1.36
diff -u -p -r1.36 zterm.c
--- libzvt/zterm.c	12 Feb 2002 16:32:20 -0000	1.36
+++ libzvt/zterm.c	13 Nov 2002 21:25:01 -0000
@@ -41,7 +41,11 @@
 
 #include <libzvt/libzvt.h>
 
+#ifdef HAS_I18N
+#define FONT "monospace 13"
+#else
 #define FONT "-misc-fixed-medium-r-normal--12-200-75-75-c-100-iso8859-1"
+#endif
 
 extern char      **environ;		
 static char      **env;
Index: libzvt/zvtterm.c
===================================================================
RCS file: /cvs/gnome/libzvt/libzvt/zvtterm.c,v
retrieving revision 1.189
diff -u -p -r1.189 zvtterm.c
--- libzvt/zvtterm.c	19 Jun 2002 19:17:20 -0000	1.189
+++ libzvt/zvtterm.c	13 Nov 2002 21:25:01 -0000
@@ -17,6 +17,28 @@
  *  License along with this program; if not, write to the Free Software
  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
+/*
+  I18N codes are added by
+	Naoyuki Ishimura <naoyuki.ishimura@sun.com>
+	Hidetoshi Tajima <hidetoshi.tajima@sun.com>
+
+   Copyright (C) 2002 Sun Microsystems, Inc.
+
+   The Gnome 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.
+
+   The Gnome 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 the Gnome Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.
+*/
 #include <config.h>
 
 /* please use K&R style indenting if you make changes.
@@ -50,6 +72,10 @@
 #include <gtk/gtkselection.h>
 #include <gtk/gtkwindow.h>
 #include <gtk/gtkbindings.h>
+#ifdef HAS_I18N
+#include <gtk/gtkimmulticontext.h>
+#include <pango/pango.h>
+#endif
 
 #include <libzvt/libzvt.h>
 
@@ -70,7 +96,11 @@
 #define d(x)
 
 /* default font */
+#ifdef HAS_I18N
+#define DEFAULT_FONT "monospace 13"
+#else
 #define DEFAULT_FONT "-misc-fixed-medium-r-semicondensed--13-120-75-75-c-60-iso8859-1"
+#endif
 
 #define PADDING 0
 
@@ -178,7 +208,11 @@ zvt_input_add (gint             source,
   GIOChannel *channel;
       
   channel = g_io_channel_unix_new (source);
-  result = g_io_add_watch (channel, condition, function, data);
+#ifdef HAS_I18N
+  /* code conversion will be done after read data */
+  g_io_channel_set_encoding (channel, NULL, NULL);
+#endif			     
+  result = g_io_add_watch_full (channel, G_PRIORITY_LOW , condition, function, data, NULL);
   g_io_channel_unref (channel);
 
   return result;
@@ -350,7 +384,7 @@ static const GtkTargetEntry target_table
   { "STRING" },
   { "TEXT" },
   { "COMPOUND_TEXT" },
-#ifdef ZVT_UTF8
+#ifdef ZVT_UTF
   { "UTF8_STRING" },
 #endif
 };
@@ -371,7 +405,7 @@ zvt_term_init (ZvtTerm *term)
   term->vx->draw_text = vt_draw_text;
   term->vx->scroll_area = vt_scroll_area;
   term->vx->selection_changed = vt_selection_changed;
-term->vx->cursor_state = vt_cursor_state;
+  term->vx->cursor_state = vt_cursor_state;
 
   term->shadow_type = GTK_SHADOW_NONE;
   term->term_window = NULL;
@@ -385,11 +419,12 @@ term->vx->cursor_state = vt_cursor_state
   term->back_gc = NULL;
   term->fore_last = 0;
   term->back_last = 0;
-  /* Deprecated */
-  /*
-  term->color_ctx = 0;
+#ifdef HAS_I18N
   term->ic = NULL;
-  */
+  term->xfontset = 0;
+  term->font_ascent = 0;
+  term->padding = PADDING;
+#endif  
 
   /* grid sizing */
   term->grid_width = term->vx->vt.width;
@@ -407,10 +442,6 @@ term->vx->cursor_state = vt_cursor_state
   term->scroll_on_keystroke = 0;
   term->scroll_on_output = 0;
   term->blink_enabled = 1;
-  /* Deprecated */
-  /*
-  term->ic = NULL;
-  */
   term->in_expose = 0;
   term->transparent = 0;
   term->shaded = 0;
@@ -447,10 +478,16 @@ term->vx->cursor_state = vt_cursor_state
   zp->background_watch_window = NULL;
   zp->background_pixmap = NULL;
     
+#ifdef HAS_I18N
+  zp->pango_context = 0;
+  zp->pango_font = 0;
+  zp->pango_font_bold = 0;
+  zp->preedit_window = 0;
+#endif
   g_object_set_data(G_OBJECT (term), "_zvtprivate", zp);
 
   /* charwidth, charheight set here */
-  zvt_term_set_font_name (term, DEFAULT_FONT);
+  zvt_term_set_font_name (term, NULL);
 
   /* scrollback position adjustment */
   term->adjustment =
@@ -642,7 +679,7 @@ term_force_size(ZvtTerm *term)
       app = gtk_widget_get_toplevel(GTK_WIDGET(term));
       g_assert (app != NULL);
 
-      hints.base_width = (GTK_WIDGET (term)->style->xthickness * 2) + PADDING;
+      hints.base_width = (GTK_WIDGET (term)->style->xthickness * 2) + term->padding;
       hints.base_height =  (GTK_WIDGET (term)->style->ythickness * 2);
       
       hints.width_inc = term->charwidth;
@@ -663,7 +700,7 @@ term_force_size(ZvtTerm *term)
     d(printf("forcing term size to %d, %d\n", term->grid_width, term->grid_height));
     d(printf("                   = %d, %d\n",
 	     (term->grid_width * term->charwidth) + 
-	     (GTK_WIDGET(term)->style->xthickness * 2) + PADDING,
+	     (GTK_WIDGET(term)->style->xthickness * 2) + term->padding,
 	     (term->grid_height * term->charheight) + 
 	     (GTK_WIDGET(term)->style->ythickness * 2)));
   }
@@ -759,13 +796,14 @@ zvt_term_destroy (GtkObject *object)
     term->adjustment = NULL;
   }
 
-  /* Deprecated */
-  /*
+#ifdef HAS_I18N
   if (term->ic) {
-    gdk_ic_destroy(term->ic);
+    g_object_unref(term->ic);
     term->ic = NULL;
   }
-  */
+  if (term->xfontset)
+    XFreeFontSet (GDK_DISPLAY(), term->xfontset);
+#endif
 
   /* release private data */
   if (zp) {
@@ -788,6 +826,12 @@ zvt_term_destroy (GtkObject *object)
     if (zp->background)
 	zvt_term_background_unload (term);
     
+#ifdef HAS_I18N
+   if (zp->pango_font)
+     pango_font_description_free(zp->pango_font);
+   if (zp->pango_font_bold)
+     pango_font_description_free(zp->pango_font_bold);
+#endif
     g_free(zp);
    g_object_set_data (G_OBJECT (term), "_zvtprivate", 0);
   }
@@ -982,7 +1026,7 @@ zvt_term_realize (GtkWidget *widget)
 
   attributes.x = widget->allocation.x;
   attributes.y = widget->allocation.y;
-  attributes.width = widget->allocation.width - (2 * widget->style->xthickness) - PADDING;
+  attributes.width = widget->allocation.width - (2 * widget->style->xthickness) - term->padding;
   attributes.height = widget->allocation.height - (2 * widget->style->ythickness);
   attributes.wclass = GDK_INPUT_OUTPUT;
   attributes.window_type = GDK_WINDOW_CHILD;
@@ -1065,21 +1109,10 @@ zvt_term_realize (GtkWidget *widget)
   /* and the initial size ... */
   term_force_size(term);
 
-  /* input context */
-#ifdef UNDEF
-  if (gdk_im_ready () && !term->ic) {
-    GdkICAttr attr;
-    
-    /* FIXME: do we have any window yet? */
-    attr.style = GDK_IM_PREEDIT_NOTHING | GDK_IM_STATUS_NOTHING;
-    attr.client_window = attr.focus_window = widget->window;
-    term->ic = gdk_ic_new(&attr, GDK_IC_ALL_REQ);
-    
-    if (!term->ic) {
-      g_warning("Can't create input context.");
-    }
-  }
-#endif /* UNDEF */
+#ifdef HAS_I18N
+  zvt_term_im_new (term);
+#endif
+
   /* if we have a delayed background set, set it here? */
   if (zp->background_queue) {
     zvt_term_background_load(term, zp->background_queue);
@@ -1129,6 +1162,11 @@ zvt_term_unrealize (GtkWidget *widget)
   g_object_unref (term->fore_gc);
   term->fore_gc = NULL;
 
+#ifdef HAS_I18N
+  if (term->ic)
+    gtk_im_context_set_client_window (term->ic, NULL);
+#endif  
+
   if (GTK_WIDGET_CLASS (parent_class)->unrealize)
     (*GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
 }
@@ -1190,11 +1228,12 @@ zvt_term_focus_in(GtkWidget *widget, Gdk
   if (term->blink_enabled && term->timeout_id == -1)
     term->timeout_id = gtk_timeout_add (500, zvt_term_cursor_blink, term);
 
-  /* Deprecated */
-  /*
-  if (term->ic)
-    gdk_im_begin (term->ic, widget->window);
-  */
+#ifdef HAS_I18N
+  if (term->ic) {
+    term->need_im_reset = TRUE;
+    gtk_im_context_focus_in (term->ic);
+  }
+#endif  
 
   return FALSE;
 }
@@ -1222,12 +1261,6 @@ zvt_term_focus_out(GtkWidget *widget, Gd
     term->timeout_id = -1;
   }
   
-  /* Deprecated */
-  /*
-  if (term->ic)
-    gdk_im_end ();
-  */
-
   return FALSE;
 }
 
@@ -1243,7 +1276,7 @@ zvt_term_size_request (GtkWidget      *w
 
   term = ZVT_TERM (widget);
 
-  requisition->width = term->charwidth + widget->style->xthickness * 2 + PADDING;
+  requisition->width = term->charwidth + widget->style->xthickness * 2 + term->padding;
   requisition->height = term->charheight + widget->style->ythickness * 2;
 
   /* debug ouput */
@@ -1283,7 +1316,7 @@ zvt_term_size_allocate (GtkWidget     *w
 			      allocation->width,
 			      allocation->height);
 
-      term_width = allocation->width - (2 * widget->style->xthickness) - PADDING;
+      term_width = allocation->width - (2 * widget->style->xthickness) - term->padding;
       term_height = allocation->height - (2 * widget->style->ythickness);
 
       /* resize the virtual terminal buffer, if its size has changed, minimal size is 1x1 */
@@ -1330,9 +1363,6 @@ zvt_term_expose (GtkWidget      *widget,
   g_return_val_if_fail (ZVT_IS_TERM (widget), FALSE);
   g_return_val_if_fail (event != NULL, FALSE);
 
-  offx = widget->style->xthickness + PADDING;
-  offy = widget->style->ythickness;
-
   d(printf("exposed!  (%d,%d) %dx%d\n",
 	   event->area.x, 
 	   event->area.y,
@@ -1343,6 +1373,9 @@ zvt_term_expose (GtkWidget      *widget,
     term = ZVT_TERM (widget);
     zp = _ZVT_PRIVATE(widget);
     
+    offx = widget->style->xthickness + term->padding;
+    offy = widget->style->ythickness;
+
     /* FIXME: may update 1 more line/char than needed */
     term->in_expose = 1;
 
@@ -1364,6 +1397,10 @@ zvt_term_expose (GtkWidget      *widget,
 
     term->in_expose = 0;
 
+#ifdef HAS_I18N
+    zvt_term_preedit_update (term);
+#endif     
+
     if (term->shadow_type != GTK_SHADOW_NONE)
       gtk_paint_shadow (widget->style, widget->window,
 		        GTK_STATE_NORMAL, term->shadow_type, 
@@ -1437,6 +1474,7 @@ zvt_term_set_scrollback (ZvtTerm *term, 
 }
 
 
+#ifndef HAS_I18N
 /* Load a set of fonts into the terminal.
  * These fonts should be the same size, otherwise it could get messy ...
 i to * if font_bold is NULL, then the font is emboldened manually (overstrike)
@@ -1504,6 +1542,7 @@ zvt_term_set_fonts_internal(ZvtTerm *ter
 
   gtk_widget_queue_resize (GTK_WIDGET (term));
 }
+#endif /* !HAS_I18N */
 
 /**
  * zvt_term_set_fonts:
@@ -1527,7 +1566,9 @@ zvt_term_set_fonts (ZvtTerm *term, GdkFo
   if (font_bold)
       gdk_font_ref (font_bold);
   
+#ifndef HAS_I18N
   zvt_term_set_fonts_internal (term, font, font_bold);
+#endif  
 }
 
 /**
@@ -1547,6 +1588,16 @@ zvt_term_set_fonts (ZvtTerm *term, GdkFo
 void
 zvt_term_set_font_name (ZvtTerm *term, char *name)
 {
+#ifdef HAS_I18N
+  gchar *font_name;
+  PangoFontDescription *font_desc;
+
+  font_name = (name == NULL || name[0] == NULL) ? DEFAULT_FONT : name;
+  
+  font_desc = pango_font_description_from_string (font_name);
+  zvt_term_set_pango_font (term, font_desc);
+  pango_font_description_free (font_desc);
+#else  
   int count;
   char c, *ptr, *rest;
   GString *newname, *outname;
@@ -1598,6 +1649,7 @@ zvt_term_set_font_name (ZvtTerm *term, c
 
   g_string_free (newname, TRUE);
   g_string_free (outname, TRUE);
+#endif /* !HAS_I18N */
 }
 
 
@@ -1633,6 +1685,15 @@ paste_received (GtkClipboard *clipboard,
 
   /* paste selection into window! */
   if (text)
+#ifdef HAS_I18N
+    {
+      if (text && *text) {
+	if (term->scroll_on_keystroke)
+	  zvt_term_scroll (term, 0);
+	zvt_term_writechild (term, text, strlen (text));
+      }
+    }
+#else      
     {
       int i, len;
       char *buf = NULL, *ctmp, *txt_cleaner;
@@ -1667,6 +1728,7 @@ paste_received (GtkClipboard *clipboard,
           g_free (buf);
         }
     }
+#endif /* !HAS_I18N */
 
   g_object_unref (G_OBJECT (term));
 }
@@ -1709,6 +1771,9 @@ zvt_term_button_press (GtkWidget      *w
 
   zvt_term_show_pointer (term);
 
+#ifdef HAS_I18N
+  zvt_term_im_reset (term);
+#endif
 
   gdk_window_get_pointer(widget->window, &x, &y, &mask);
   x /= term->charwidth;
@@ -2093,8 +2158,30 @@ zvt_term_selection_clear (GtkWidget *wid
 #ifdef ZVT_UTF
 /* perform data-conversion on the selection */
 static char *
-zvt_term_convert_selection(ZvtTerm *term, int type, int *outlen)
+zvt_term_convert_selection (ZvtTerm *term, int type, int *outlen)
 {
+#ifdef HAS_I18N
+  switch (type) {
+  case 1:
+    /* This case should never happen...*/
+    g_warning ("return UTF-32 text (contain NULL bytes) to selection requestor\n");
+    *outlen = term->vx->selection_size;
+    return (gchar *)term->vx->selection_data;
+  default:
+    {
+      /* 4 is max bytesize of one UTF-8 character of UTF-16(2byte Unicode)
+	 code range */
+      gchar *utf8_ptr = g_malloc (term->vx->selection_size * 4);
+      gint i, expand_index = 0;
+      for (i = 0; i < term->vx->selection_size; i++) {
+	expand_index += g_unichar_to_utf8 (term->vx->selection_data[i], &utf8_ptr[expand_index]);
+      }
+      utf8_ptr[expand_index] = '\0';
+      *outlen = expand_index;
+      return utf8_ptr;
+    }
+  }
+#else
   char *out;
   int i;
   uint32 c;
@@ -2177,8 +2264,9 @@ zvt_term_convert_selection(ZvtTerm *term
   }
 
   return out;
+#endif /* !HAS_I18N */
 }
-#endif
+#endif /* ZVT_UTF */
 
 /* supply the current selection to the caller */
 static void
@@ -2207,8 +2295,8 @@ zvt_term_selection_get (GtkWidget       
 /**
  * zvt_term_writechild:
  * @term: A &ZvtTerm widget.
- * @data: Data to write.
- * @len: Length of data to write.
+ * @utf8_data: Data to write, encoded in UTF-8.
+ * @utf8_len: Length of data to write.
  *
  * Writes @len bytes of data, starting from @data to the subordinate
  * child process.  If the child is unable to handle all of the data
@@ -2218,13 +2306,23 @@ zvt_term_selection_get (GtkWidget       
  * Return Value: The number of bytes written initially.
  */
 int
-zvt_term_writechild(ZvtTerm *term, char *data, int len)
+zvt_term_writechild(ZvtTerm *term, char *utf8_data, int utf8_len)
 {
   int length;
   struct _zvtprivate *zp;
+  gchar *data = 0;
+  gssize len = 0;
+  gsize bytes_written;
 
   zp = _ZVT_PRIVATE(term);
 
+  data = zvt_term_locale_from_utf8 (utf8_data, strlen(utf8_data),
+				    NULL, &bytes_written, NULL);
+  if (!data)
+    return 0;
+
+  len = strlen (data);
+
   /* if we are already pasting something, make sure we append ... */
   if (zp->paste_id == -1)
     length = vt_writechild(&term->vx->vt, data, len);
@@ -2234,7 +2332,7 @@ zvt_term_writechild(ZvtTerm *term, char 
   d(printf("wrote %d bytes of %d bytes\n", length, len));
 
   if (length>=0 && length < len) {
-	  
+
     if (zp->paste_id == -1) {
       zp->paste = g_malloc(len-length);
       zp->paste_offset = 0;
@@ -2249,6 +2347,7 @@ zvt_term_writechild(ZvtTerm *term, char 
       zp->paste_len += (len - length);
     }
   }
+  g_free (data);
   return length;
 }
 
@@ -2453,7 +2552,8 @@ zvt_term_closepty (ZvtTerm *term)
   return vt_closepty (&term->vx->vt);
 }
 
-static void
+/* make it public for input method's commit event handler */
+void
 zvt_term_scroll (ZvtTerm *term, int n)
 {
   gfloat new_value = 0;
@@ -2529,7 +2629,13 @@ zvt_term_key_press (GtkWidget *widget, G
   if(!gtk_bindings_activate(GTK_OBJECT(widget),
                             event->keyval,
                             event->state)){
-  
+    
+#ifdef HAS_I18N
+    if (term->ic && gtk_im_context_filter_keypress (term->ic, event)) {
+      term->need_im_reset = TRUE;
+      return TRUE;
+    }
+#endif    
   switch (event->keyval) {
   case GDK_BackSpace:
     if (term->backspace_binding == ZVT_ERASE_CONTROL_H ||
@@ -2730,6 +2836,9 @@ zvt_term_key_press (GtkWidget *widget, G
   if (handled && p>buffer) {
     vt_writechild(&vx->vt, buffer, (p-buffer));
     if (term->scroll_on_keystroke) zvt_term_scroll (term, 0);
+#ifdef HAS_I18N
+    zvt_term_im_reset (term);
+#endif
   }
   }
 
@@ -2765,7 +2874,11 @@ zvt_term_real_copy_clipboard (ZvtTerm *t
   if (term->vx->selection_size == 0)
     return;
 
+#ifdef HAS_I18N
+  text = zvt_term_convert_selection (term, 0, &len);
+#else
   text = zvt_term_convert_selection (term, 1, &len);
+#endif
 
   gtk_clipboard_set_text (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD), text, len);
 
@@ -2928,15 +3041,31 @@ static gboolean
 zvt_term_readdata (GIOChannel *source, GIOCondition condition, gpointer data)
 {
   gboolean update;
+#ifndef HAS_I18N  
   gchar buffer[4096];
   gint count, saveerrno;
+#endif  
+  gsize count, saveerrno;
   struct _vtx *vx;
   ZvtTerm *term;
+#ifdef HAS_I18N
+  gint data_size = 0;
+  GIOStatus io_status;
+  GError *io_error = NULL;
+  G_CONST_RETURN char *locale_encoding;
+  gchar buf[4096];
+  gchar *buffer;
+  gsize bytes_read;
+  gsize bytes_written;
+  gboolean no_need_convert = FALSE;
+  gsize left_len;
+#else
   gint fd;
 
   d( printf("zvt_term_readdata\n") );
 
   fd = g_io_channel_unix_get_fd (source);
+#endif /* HAS_I18N */
   term = (ZvtTerm *) data;
 
   if (term->input_id == -1)
@@ -2949,6 +3078,118 @@ zvt_term_readdata (GIOChannel *source, G
 
   vt_cursor_state (term, 0);
   vt_match_highlight(term->vx, 0);
+#ifdef HAS_I18N
+  no_need_convert = g_get_charset (&locale_encoding);
+
+  left_len = 0;
+  count = 0;
+
+  while (data_size < (8 * 1024)) {
+    g_clear_error (&io_error);
+    count = 0;
+    io_status = g_io_channel_read_chars (source, &buf[left_len],
+					 4096 - left_len,
+					 &count, &io_error);
+    if (G_IO_STATUS_EOF == io_status)
+      break;
+
+    if (io_status == G_IO_STATUS_ERROR) {
+      if (io_error != NULL)
+	g_warning ("%s\n", io_error->message);
+
+      g_clear_error (&io_error);
+      g_io_channel_flush (source, &io_error);
+      break;
+    } else if (io_status == G_IO_STATUS_AGAIN) {
+      break;
+    }
+
+    data_size += count;
+
+    count += left_len;
+    if (no_need_convert || g_utf8_validate (buf, -1, NULL))
+      buffer = g_strdup (buf);
+    else {
+      int conv_len = 0;
+      buffer = 0;
+      while (1) {
+	gchar *buffer2 = NULL;
+	GError *conv_error = NULL;
+	buffer2 = zvt_term_locale_to_utf8 (&buf[conv_len], count,
+					   &bytes_read, &bytes_written,
+					   &conv_error);
+
+	left_len = count - bytes_read;
+	if (left_len == 0 && buffer2 && buffer2[0]) {
+	  if (buffer) {
+	    gchar *tmp;
+	    tmp = g_strconcat(buffer, buffer2, NULL);
+	    g_free (buffer);
+	    buffer = tmp;
+	  } else
+	    buffer = g_strdup(buffer2);
+	  g_free (buffer2);
+	  break;
+	}
+
+	if (conv_error) {
+	  switch (errno) {
+	  case EILSEQ:
+	    g_warning ("%s\n", conv_error->message);
+	    g_clear_error (&conv_error);
+	    /*
+	      Invalid byte sequence in conversion input,
+	      and buf[conv_len + bytes_read] should be the 1st occurance 
+	      of invalid byte sequence.
+	      Hence, we should be able to do simply:
+	    */
+	    buf[conv_len + bytes_read] = '?';
+	    /*
+	      However, some iconv modules have a bug and
+	      don't stop at the 1st occurance of invalid byte
+	      sequence.
+
+	      This could cause an infinite loop, please consult
+	      iconv man page and have those iconv modules fixed.
+	    */
+	    break;
+	  default:
+	    break;
+	  }
+	} else {
+	  if (buffer2 && buffer2[0]) {
+	    conv_len += bytes_read;
+	    count -= bytes_read;
+	    if (buffer) {
+	      gchar *tmp;
+	      tmp = g_strconcat(buffer, buffer2, NULL);
+	      g_free (buffer);
+	      buffer = tmp;
+	    } else
+	      buffer = g_strdup(buffer2);
+
+	    g_free (buffer2);
+	  } else
+	    buf[conv_len + bytes_read] = '?';
+	}
+      }
+      if (buffer == NULL)
+	buffer = g_strdup (buf);
+
+      count = strlen (buffer);
+    }
+    update = TRUE;
+    saveerrno = errno;
+    vt_parse_vt (&vx->vt, buffer, count);
+
+    if (g_signal_has_handler_pending (G_OBJECT(term),
+				      term_signals[GOT_OUTPUT], 0, TRUE))
+      zvt_term_got_output (term, buffer, count);
+
+    g_free (buffer);
+    buffer = NULL;
+  }
+#else
   while ( (saveerrno == EAGAIN) && (count = read (fd, buffer, 4096)) > 0)  {
     update = TRUE;
     saveerrno = errno;
@@ -2958,6 +3199,7 @@ zvt_term_readdata (GIOChannel *source, G
 				   term_signals[GOT_OUTPUT], 0, TRUE))
 	zvt_term_got_output(term, buffer, count);
   }
+#endif
 
   if (update) {
     if (GTK_WIDGET_DRAWABLE (term)) {
@@ -3189,7 +3431,7 @@ vt_cursor_state(void *user_data, int sta
         vt_draw_cursor(term->vx, FALSE);
         if (term->vx->vt.scrollbackold == 0 &&
 	    term->vx->vt.cursorx < term->vx->vt.width) {
-	  int offx = widget->style->xthickness + PADDING;
+	  int offx = widget->style->xthickness + term->padding;
 	  int offy = widget->style->ythickness;
 	  gdk_draw_rectangle (widget->window,
 			      term->fore_gc, 0,
@@ -3201,6 +3443,9 @@ vt_cursor_state(void *user_data, int sta
 			      term->charheight - 2);
 	}
       }
+#ifdef HAS_I18N
+      zvt_term_im_cursor_location (term);
+#endif
       term->cursor_on = state;
     }
   }
@@ -3242,13 +3487,20 @@ vt_draw_text(void *user_data, struct vt_
   if (len+col>vx->vt.width)
     len = vx->vt.width-col;
 
-  /* rendering offsetx */
-  x = col * term->charwidth;
-  y = row * term->charheight + term->font->ascent;
-  offx = widget->style->xthickness + PADDING;
-  offy = widget->style->ythickness;
+#ifdef HAS_I18N
+  if (col > 0 && zvt_localechar_iswide(line->data[col] & VTATTR_DATAMASK)) {
+    col--;
+    len++;
+  }
+#endif
+  
   zp = _ZVT_PRIVATE(term);
 
+  zvt_term_get_baseline_offset (term, row, col, &x, &y);
+
+  offx = widget->style->xthickness + term->padding;
+  offy = widget->style->ythickness;
+
   if (attr & VTATTR_BOLD)  {
     or = 8;
     f = term->font_bold;
@@ -3363,9 +3615,14 @@ vt_draw_text(void *user_data, struct vt_
   /* make sure we have the space to expand the text */
   if (zp->text_expand==0 || zp->text_expandlen<len) {
     zp->text_expand = g_realloc(zp->text_expand, len*sizeof(uint32));
+    memset(zp->text_expand, 0, len *sizeof(uint32));
     zp->text_expandlen = len;
   }
 
+#ifdef HAS_I18N
+  zvt_term_draw_text (term, line, row, col, zp->text_expand, len,
+		      x, y, offx, offy, fgc, dofill, overstrike);
+#else  
   /* This funtion is provided so that we can get hokked up with the 
   real_drawable used when backing store is used, which seems to be the 
   case here, when using backing store the direct X calls needs protection
@@ -3455,6 +3712,7 @@ vt_draw_text(void *user_data, struct vt_
   }
   offx+=real_offx;
   offy+=real_offy;
+#endif /* !HAS_I18N */
 
   /* check for underline */
   if (attr&VTATTR_UNDERLINE) {
@@ -3505,7 +3763,7 @@ vt_scroll_area(void *user_data, int firs
 	  count,firstrow,offset,fill));
 
   width = term->charwidth * term->vx->vt.width;
-  offx = widget->style->xthickness + PADDING;
+  offx = widget->style->xthickness + term->padding;
   offy = widget->style->ythickness;
 
   /* "scroll" area */
--- /dev/null	2002-11-13 13:13:14.000000000 -0800
+++ libzvt/zvti18n.c	2002-11-13 13:15:38.031749000 -0800
@@ -0,0 +1,905 @@
+/*
+ * Copyright (C) 2001,2002 Red Hat, Inc.
+ *
+ * This 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 program 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+/*  zvti18n.c - Zed's Virtual Terminal
+ *  Copyright (C) 1998  Michael Zucchi
+ *
+ *  i18n functions for the zvtterm widget.
+ *
+  Author: Naoyuki Ishimura <naoyuki.ishimura@sun.com>
+	  Hidetoshi Tajima <hidetoshi.tajima@sun.com>
+
+   Copyright (C) 2002 Sun Microsystems, Inc.
+
+   The Gnome 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.
+
+   The Gnome 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 the Gnome Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.
+*/
+#include <stdlib.h>
+#include <gtk/gtkmain.h>
+#include <gdk/gdkx.h>
+#include <libzvt/libzvt.h>
+#include <gtk/gtkimmulticontext.h>
+#include <pango/pangox.h>
+
+#ifdef HAS_I18N
+
+static gboolean
+localechar_iswide_internal (gchar *mbchar, int mb_len)
+{
+  wchar_t wchar_buf[1];
+  gint wc_width;
+  gboolean ret = FALSE;
+
+  if (mbchar && mbtowc (wchar_buf, mbchar, mb_len) > 0)
+    {
+      wc_width = wcwidth (wchar_buf[0]);
+      ret = wc_width > 1 ? TRUE : FALSE;
+    }
+
+  return ret;
+}
+
+gboolean
+zvt_localechar_iswide (gunichar c)
+{
+#ifdef USE_PANGO_LAYOUT
+  return g_unichar_iswide (c);
+#else
+  gchar utf8_buf[6];
+  wchar_t wchar_buf[1];
+  gint wc_width;
+  gsize bytes_written;
+  GError *io_error = NULL;
+  gint len;
+  gchar *mbchar;
+  gboolean ret = FALSE;
+
+  if (c < 0x80)			/* ascii */
+    return ret;
+
+  len = g_unichar_to_utf8 (c, utf8_buf);
+  utf8_buf[len] = 0;
+  mbchar = zvt_term_locale_from_utf8 (utf8_buf, len,
+				      NULL, &bytes_written, &io_error);
+
+  ret = localechar_iswide_internal (mbchar, bytes_written);
+
+  g_free (mbchar);
+
+  return ret;
+#endif /* USE_PANGO_LAYOUT */
+}
+
+gint
+zvt_column_preedit_string (gchar *utf8_ptr, gint length) {
+  gunichar uc;
+  gchar *p = utf8_ptr;
+  gint count = 0;
+
+  do {
+    if (*p == 0)
+      break;
+    
+    uc = g_utf8_get_char(p);
+    if (g_unichar_iswide (uc))
+      count++;
+    count++;
+  } while ((p = g_utf8_next_char(p)) && (p - utf8_ptr) < length);
+
+  return count;
+}
+
+gint
+zvt_column_from_utf8 (gchar *utf8_ptr, gint length) {
+  gunichar uc;
+  gchar *p = utf8_ptr;
+  gint count = 0;
+
+  do {
+    if (*p == 0)
+      break;
+    
+    uc = g_utf8_get_char(p);
+    if (zvt_localechar_iswide (uc))
+      count++;
+    count++;
+  } while ((p = g_utf8_next_char(p)) && (p - utf8_ptr) < length);
+
+  return count;
+}
+
+void
+zvt_term_get_baseline_offset (ZvtTerm *term, int row, int col,
+			      gint *offset_x, gint *offset_y)
+{
+  /* rendering offsetx */
+  *offset_x = col * term->charwidth;
+
+#ifdef USE_PANGO_LAYOUT
+  /* pango origin does not need to be added ascent */
+  *offset_y = row * term->charheight;
+#else
+  *offset_y = row * term->charheight + term->font_ascent;
+#endif
+  return;
+}
+
+#include <locale.h>
+
+static gboolean
+zvt_term_is_c_locale ()
+{
+  gchar *locale = setlocale (LC_CTYPE, NULL);
+  return (strcmp ("C", locale) == 0 || strcmp ("POSIX", locale) == 0);
+}
+
+gchar *
+zvt_term_locale_from_utf8 (const gchar *utf8_ptr, gssize utf8_len,
+			   gsize *bytes_read, gsize *bytes_written,
+			   GError **error)
+{
+  gchar *locale_format;
+  if (zvt_term_is_c_locale())
+    locale_format = g_convert (utf8_ptr, utf8_len,
+			       "ISO-8859-1", "UTF-8",
+			       bytes_read, bytes_written, error);
+  else
+    locale_format = g_locale_from_utf8 (utf8_ptr, utf8_len, bytes_read,
+					bytes_written, error);
+  return locale_format;
+}
+
+gchar *
+zvt_term_locale_to_utf8 (const gchar *locale_ptr, gssize locale_len,
+			 gsize *bytes_read, gsize *bytes_written,
+			 GError **error)
+{
+  gchar *utf8_format;
+  if (zvt_term_is_c_locale())
+    utf8_format = g_convert (locale_ptr, locale_len,
+			     "UTF-8", "ISO-8859-1",
+			     bytes_read, bytes_written, error);
+  else
+    utf8_format = g_locale_to_utf8 (locale_ptr, locale_len, bytes_read,
+				    bytes_written, error);
+  return utf8_format;
+}
+
+void
+zvt_term_draw_text (ZvtTerm *term, struct vt_line *line, int row, int col,
+		    gchar *utf8_ptr, int len, int x, int y, int offx,
+		    int offy, GdkGC *fgc, int dofill, int overstrike)
+{
+  GtkWidget *widget;
+  glong read_count, write_count, i, utf8_len, expand_index = 0;
+
+#ifdef USE_PANGO_LAYOUT
+  PangoLayout *layout;
+  struct _zvtprivate *zp = 0;
+  zp = _ZVT_PRIVATE(term);
+#endif
+
+  widget = GTK_WIDGET (term);
+
+  for (i = col; i < col + len; i++) {
+    gunichar uc = line->data[i] & VTATTR_DATAMASK;
+    if (uc == 0 && !((line->data[i] & VTATTR_MASK) & VTATTR_UTF16_HALF)) {
+      utf8_len = 1;
+      utf8_ptr[expand_index] = ' ';
+    } else if (uc == '\t') {
+      utf8_len = 1;
+      utf8_ptr[expand_index] = ' ';
+    } else {
+      if (line->data[i] & VTATTR_UTF16_HALF) {
+	uc = (((uc << 16) & 0xffff0000) | (line->data[++i] & VTATTR_DATAMASK));
+      }
+      utf8_len = g_unichar_to_utf8 (uc, &(utf8_ptr[expand_index]));
+    }
+    expand_index += utf8_len;
+  }
+
+#ifdef USE_PANGO_LAYOUT
+  zp->pango_context = gdk_pango_context_get();
+  pango_context_set_language (zp->pango_context,
+			      gtk_get_default_language ());
+  gdk_pango_context_set_colormap(zp->pango_context, term->color_map);
+  pango_context_set_font_description(zp->pango_context, zp->pango_font);
+  layout = pango_layout_new(zp->pango_context);
+  pango_layout_set_text(layout, utf8_ptr, expand_index);
+
+  if (dofill) {
+    GdkColor *fcolor = &(term->colors[fore]);
+    GdkColor *bcolor = &(term->colors[back]);
+    gdk_draw_layout_with_colors(widget->window, fgc, x + offx, y + offy, layout, fcolor, bcolor);
+  } else {
+    gdk_draw_layout(widget->window, fgc, x + offx, y + offy, layout);
+  }
+
+  g_object_unref (layout);
+#else
+  if (utf8_ptr) {
+    GError *error = NULL;
+    gsize locale_format_len = 0;
+    gchar *locale_format;
+    G_CONST_RETURN char *locale_encoding;
+
+    if (g_get_charset(&locale_encoding)) {
+      locale_format = g_strdup(utf8_ptr);
+      locale_format_len = expand_index;
+    } else
+      locale_format = zvt_term_locale_from_utf8 (utf8_ptr, expand_index,
+						 NULL, &locale_format_len, &error);
+    if (error)
+      {
+	g_warning ("Error converting from utf8: %s\n", error->message);
+	if (error)
+	  g_error_free (error);
+      }
+    else
+      {
+	gint real_offx, real_offy;
+	GdkDrawable *real_drawable;
+	if (term->xfontset) {
+	  /* call XmbDrawString here with XFontSet */
+	  
+	  gdk_window_get_internal_paint_info(widget->window,
+					     &real_drawable,
+					     &real_offx,&real_offy);
+	  offx-=real_offx;
+	  offy-=real_offy;
+
+#define GET_VALUE_MASK	(GCFunction | GCForeground | GCBackground | GCFillStyle)
+	  {
+	    int startx = offx + x;
+	    gchar locale_char;
+	    gchar *bufp = locale_format;
+	    gchar *endp = locale_format + locale_format_len;
+	    int mb_len;
+
+	    Display *display = GDK_WINDOW_XDISPLAY(widget->window);
+	    Drawable drawable = GDK_WINDOW_XWINDOW(real_drawable);
+	    XGCValues  values;
+	    GC gc = XCreateGC(display, drawable, 0, NULL);
+
+	    XGetGCValues(display, GDK_GC_XGC(fgc),
+			 GET_VALUE_MASK, &values);
+
+	    XSetFunction(display, gc, GXcopy);
+	    XSetFillStyle(display, gc, FillSolid);
+	    XSetForeground(display, gc, values.background);
+
+	    while (bufp < endp && (mb_len = mblen(bufp, MB_CUR_MAX)) > 0) {
+	      /* draw one multi-byte character at a time, with fill
+		 if we can */
+	      int text_width, spacing;
+	      int column_width_of_char;
+	      XRectangle extent;
+	      gboolean is_wide;
+
+	      /* fill spacing to the next character if any */
+	      text_width = XmbTextExtents(term->xfontset, bufp, mb_len,
+					  0, &extent);
+	      is_wide = localechar_iswide_internal (bufp, mb_len);
+	      spacing = term->charwidth * (is_wide ? 2 : 1) - extent.width;
+
+	      if (dofill) {
+		XmbDrawImageString(GDK_WINDOW_XDISPLAY(widget->window),
+				   GDK_WINDOW_XWINDOW(real_drawable),
+				   term->xfontset, GDK_GC_XGC(fgc),
+				   startx, offy + y,
+				   bufp, mb_len);
+	      } else {
+		XmbDrawString(GDK_WINDOW_XDISPLAY(widget->window),
+			      GDK_WINDOW_XWINDOW(real_drawable),
+			      term->xfontset, GDK_GC_XGC(fgc),
+			      startx, offy + y,
+			      bufp, mb_len);
+	      }
+	      if (dofill && spacing > 0)
+		XFillRectangle(GDK_WINDOW_XDISPLAY(widget->window),
+			       drawable,
+			       gc, startx + extent.width,
+			       offy + y + extent.y,
+			       spacing, extent.height);
+	      if (overstrike)
+		XmbDrawString(GDK_WINDOW_XDISPLAY(widget->window),
+			      GDK_WINDOW_XWINDOW(real_drawable),
+			      term->xfontset, GDK_GC_XGC(fgc),
+			      startx, offy + y,
+			      bufp, mb_len);
+	      startx += term->charwidth * (is_wide ? 2 : 1);
+	      bufp += mb_len;
+	    }
+	    XFreeGC(display, gc);
+	  }
+	  offx+=real_offx;
+	  offy+=real_offy;
+	}
+      }
+    g_free (locale_format);
+  }
+#endif /* !USE_PANGO_LAYOUT */
+}
+
+static void
+zvt_term_commit_handler (GtkIMContext  *context,
+			 const gchar   *str,
+			 ZvtTerm       *term)
+{
+  gsize length = 0;
+  gchar *locstr = zvt_term_locale_from_utf8 (str, -1, NULL, &length, NULL);
+
+  if (length > 0) {
+    vt_writechild (&term->vx->vt, locstr, length);
+    if (term->scroll_on_keystroke) zvt_term_scroll (term, 0);
+  }
+  g_free (locstr);
+}
+
+static GdkWindow *
+zvt_make_preedit_window (GtkWidget *widget) {
+    GdkWindowAttr window_attr;
+    gint attr_mask;
+    window_attr.wclass = GDK_INPUT_OUTPUT;
+    window_attr.window_type = GDK_WINDOW_CHILD;
+    window_attr.event_mask = GDK_EXPOSURE_MASK;
+    window_attr.visual = gtk_widget_get_visual(widget);
+    window_attr.colormap = gtk_widget_get_colormap(widget);
+    attr_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
+    return gdk_window_new(widget->window, &window_attr, attr_mask);
+}
+
+static void
+zvt_resize_preedit_window (ZvtTerm *term, GdkWindow *window,
+			   gint x, gint y, gint width) {
+  gint space;
+
+  if (width > term->vx->vt.width)
+    width = term->vx->vt.width;
+
+  space = term->vx->vt.width - term->vx->vt.cursorx;
+  if (space < width)
+    x -= (width - space) * term->charwidth;
+
+  gdk_window_move_resize(window, x, y,
+			 width * term->charwidth, term->charheight);
+}
+
+#define PREEDIT_UNDERLINE_WIDTH 1
+
+static void
+zvt_term_preedit_changed_handler (GtkIMContext *context,
+				  ZvtTerm *term)
+{
+  gchar *preedit_string = NULL;
+  gint cursor_pos = 0;
+  struct _vtx *vx;
+  PangoAttrList *feedback_list = NULL;
+  PangoAttrIterator *iter;
+  PangoLayout *layout;
+  struct _zvtprivate *zp = 0;
+  gint x, y;
+  gint preedit_len, preedit_col_len, preedit_advanced;
+  gint attr_start, attr_end, attr_length, attr_x;
+  struct vt_line *line;
+
+  zp = _ZVT_PRIVATE(term);
+
+  gtk_im_context_get_preedit_string (context,
+				     &preedit_string,
+				     &feedback_list,
+				     &cursor_pos);
+  
+  preedit_len = strlen(preedit_string);
+  if (preedit_string == NULL || preedit_len <= 0) {
+    if (zp->preedit_window != NULL && gdk_window_is_visible(zp->preedit_window)) {
+      gdk_window_hide(zp->preedit_window);
+    }
+    return;
+  }
+
+  if (zp->preedit_window == NULL) { 
+    /* create over the spot preedit window */
+    zp->preedit_window = zvt_make_preedit_window(GTK_WIDGET(term));
+  }
+
+  preedit_col_len = zvt_column_preedit_string (preedit_string, preedit_len);
+  cursor_pos = CLAMP (cursor_pos, 0, g_utf8_strlen (preedit_string, -1));
+  
+  /* adjust size of preedit window */
+  vx = term->vx;
+  x = vx->vt.cursorx * term->charwidth + GTK_WIDGET(term)->style->xthickness + term->padding;
+  y = vx->vt.cursory * term->charheight + GTK_WIDGET(term)->style->ythickness;
+
+  zvt_resize_preedit_window(term, zp->preedit_window, x, y, preedit_col_len);
+  gdk_window_show(zp->preedit_window);
+
+  /* draw preedit string with attribute */ 
+  zp->pango_context = gdk_pango_context_get();
+  pango_context_set_language (zp->pango_context,
+			      gtk_get_default_language ());
+  gdk_pango_context_set_colormap(zp->pango_context, term->color_map);
+
+  pango_context_set_font_description(zp->pango_context, zp->pango_font);
+
+  layout = pango_layout_new(zp->pango_context);
+  iter = pango_attr_list_get_iterator(feedback_list);
+
+  attr_x = 0;
+  do {
+    GSList *attrs = NULL;
+    GSList *attr_list;
+    gboolean is_reverse, is_underline;
+
+    pango_attr_iterator_range(iter, &attr_start, &attr_end);
+    attr_end = CLAMP(attr_end, attr_start, preedit_len);
+    attr_length = attr_end - attr_start;
+    if (attr_length <= 0)
+      continue;
+
+    pango_attr_iterator_get_font (iter, zp->pango_font, NULL, &attrs);
+    is_underline = FALSE;
+    is_reverse = FALSE;
+
+    attr_list = attrs;
+    while (attr_list) {
+      PangoAttribute *attr = attr_list->data;
+      switch(attr->klass->type) {
+      case PANGO_ATTR_FOREGROUND:
+	/* FIX Later: should keep color */
+	is_reverse = TRUE;
+	break;
+      case PANGO_ATTR_BACKGROUND:
+	/* FIX Later: should keep color */
+	is_reverse = TRUE;
+	break;
+      case PANGO_ATTR_UNDERLINE:
+	is_underline = TRUE;
+	break;
+      case PANGO_ATTR_STRIKETHROUGH:
+	break;
+      default:
+	g_warning("Unknown preedit attribute type: %d\n", attr->klass->type);
+	break;
+      }
+      pango_attribute_destroy(attr);
+      attr_list = attr_list->next;
+    }
+
+    g_slist_free (attrs);
+
+    pango_layout_set_text(layout, preedit_string + attr_start, attr_length);
+    if (is_reverse) {
+      gdk_draw_layout_with_colors(zp->preedit_window, term->fore_gc, attr_x, 0, layout,
+				  &(term->colors[17]), &(term->colors[16]));
+    } else {
+      gdk_draw_layout_with_colors(zp->preedit_window, term->fore_gc, attr_x, 0, layout,
+				  &(term->colors[16]), &(term->colors[17]));
+    }
+
+    preedit_advanced = zvt_column_from_utf8 (preedit_string + attr_start, attr_length) * term->charwidth;
+    if (is_underline) {
+      gdk_gc_set_foreground(term->fore_gc, &(term->colors[16]));
+      gdk_draw_rectangle(zp->preedit_window, term->fore_gc, 1,
+			 attr_x, term->charheight - PREEDIT_UNDERLINE_WIDTH,
+			 preedit_advanced, PREEDIT_UNDERLINE_WIDTH);
+    }
+    attr_x +=  preedit_advanced;
+  } while(pango_attr_iterator_next(iter));
+
+  pango_attr_iterator_destroy (iter);
+  pango_attr_list_unref (feedback_list);
+  g_object_unref (layout);
+  g_free (preedit_string);
+}
+
+/* Public functions for Input Methods */
+void
+zvt_term_im_new (ZvtTerm *term)
+{
+  struct _zvtprivate *zp;
+  zp = _ZVT_PRIVATE(term);
+
+  if (!term->ic) {
+    term->ic = gtk_im_multicontext_new ();
+    g_signal_connect (term->ic, "commit",
+		      G_CALLBACK (zvt_term_commit_handler), term);
+
+    gtk_im_context_set_client_window (term->ic, GTK_WIDGET(term)->window);
+    
+    g_signal_connect (G_OBJECT(term->ic), "preedit-changed",
+		      GTK_SIGNAL_FUNC(zvt_term_preedit_changed_handler), term);
+    zp->preedit_window = 0;
+  }
+  return;
+}
+
+void
+zvt_term_im_cursor_location (ZvtTerm *term)
+{
+  /* 
+     Some input methods may use this position to show their
+     status-bar and lookup-choice windows.
+     Adding +1 offset to both cursorx and cursory to keep
+     these windows from hiding the text at the cursor location.
+  */
+  if (term->ic) {
+    GdkRectangle area;
+    area.x = (term->vx->vt.cursorx + 1) * term->charwidth;
+    area.y = (term->vx->vt.cursory + 1) * term->charheight;
+    area.width = area.height = 0;
+    gtk_im_context_set_cursor_location (term->ic, &area);
+  }
+}
+
+void
+zvt_term_preedit_update (ZvtTerm *term)
+{
+  struct _zvtprivate *zp;
+  zp = _ZVT_PRIVATE(term);
+
+  if (zp->preedit_window != NULL &&
+      gdk_window_is_visible (zp->preedit_window))
+    zvt_term_preedit_changed_handler (term->ic, term);
+}
+
+void
+zvt_term_im_reset (ZvtTerm *term)
+{
+#ifdef NEED_IM_RESET
+  if (term->ic && term->need_im_reset) {
+    term->need_im_reset = FALSE;
+    gtk_im_context_reset (term->ic);
+  }
+#endif
+}
+
+void
+zvt_term_im_free (ZvtTerm *term)
+{
+  g_warning("not implemented yet");
+}
+
+/* FontSet */
+
+/*
+  xlfd_from_pango_font_description copied from vte, which was
+  written by nalin@redhat.com, and added some codes.
+*/
+static char *
+xlfd_from_pango_font_description(GtkWidget *widget,
+				 const PangoFontDescription *fontdesc)
+{
+	char *spec;
+	PangoContext *context;
+	PangoFont *font;
+	PangoXSubfont *subfont_ids;
+	PangoFontMap *fontmap;
+	int *subfont_charsets, i, count = 0;
+	char *xlfd = NULL, *tmp, *subfont;
+	char *encodings[] = {
+		"ascii-0",
+		"big5-0",
+		"dos-437",
+		"dos-737",
+		"gb18030.2000-0",
+		"gb18030.2000-1",
+		"gb2312.1980-0",
+		"iso8859-1",
+		"iso8859-2",
+		"iso8859-3",
+		"iso8859-4",
+		"iso8859-5",
+		"iso8859-7",
+		"iso8859-8",
+		"iso8859-9",
+		"iso8859-10",
+		"iso8859-15",
+		"iso10646-0",
+		"iso10646-1",
+		"jisx0201.1976-0",
+		"jisx0208.1983-0",
+		"jisx0208.1990-0",
+		"jisx0208.1997-0",
+		"jisx0212.1990-0",
+		"jisx0213.2000-1",
+		"jisx0213.2000-2",
+		"koi8-r",
+		"koi8-u",
+		"koi8-ub",
+		"ksc5601.1987-0",
+		"ksc5601.1992-3",
+		"tis620-0",
+		"iso8859-13",
+		"microsoft-cp1251"
+		"misc-fontspecific",
+	};
+#if XlibSpecificationRelease >= 6
+	XOM xom;
+#endif
+	g_return_val_if_fail(fontdesc != NULL, NULL);
+	g_return_val_if_fail(GTK_IS_WIDGET(widget), NULL);
+
+	context = gtk_widget_get_pango_context(GTK_WIDGET(widget));
+
+	pango_context_set_language (context,
+				    gtk_get_default_language ());
+	fontmap = pango_x_font_map_for_display(GDK_DISPLAY());
+	if (fontmap == NULL) {
+		return g_strdup("fixed");
+	}
+
+	font = pango_font_map_load_font(fontmap, context, fontdesc);
+	if (font == NULL) {
+		return g_strdup("fixed");
+	}
+
+#if XlibSpecificationRelease >= 6
+	xom = XOpenOM (GDK_DISPLAY(), NULL, NULL, NULL);
+	if (xom) {
+	  XOMCharSetList cslist;
+	  int n_encodings = 0;
+
+	  cslist.charset_count = 0;
+	  XGetOMValues (xom,
+			XNRequiredCharSet, &cslist,
+			NULL);
+	  n_encodings = cslist.charset_count;
+	  if (n_encodings) {
+	    char **xom_encodings = g_malloc (sizeof(char*) * n_encodings);
+
+	    for (i = 0; i < n_encodings; i++)
+	      xom_encodings[i] = g_ascii_strdown (cslist.charset_list[i], -1);
+	    count = pango_x_list_subfonts(font, xom_encodings, n_encodings,
+					  &subfont_ids, &subfont_charsets);
+
+	    for(i = 0; i < n_encodings; i++)
+	      g_free (xom_encodings[i]);
+	    g_free (xom_encodings);
+	  }
+	  XCloseOM (xom);
+	}
+#endif
+	if (count == 0)
+	  count = pango_x_list_subfonts(font, encodings, G_N_ELEMENTS(encodings),
+					&subfont_ids, &subfont_charsets);
+
+	for (i = 0; i < count; i++) {
+		subfont = pango_x_font_subfont_xlfd(font, subfont_ids[i]);
+		if (xlfd) {
+			tmp = g_strconcat(xlfd, ",", subfont, NULL);
+			g_free(xlfd);
+			g_free(subfont);
+			xlfd = tmp;
+		} else {
+			xlfd = subfont;
+		}
+	}
+
+	spec = pango_font_description_to_string(fontdesc);
+
+	if (subfont_ids != NULL) {
+		g_free(subfont_ids);
+	}
+	if (subfont_charsets != NULL) {
+		g_free(subfont_charsets);
+	}
+	g_free(spec);
+
+	return xlfd;
+}
+
+static const gchar *ASCII_CHARACTERS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ !\"#$%&'()*+,-./:;<=>?@\\]^_`{}~";
+
+static const gchar *DEFAULT_XLFD_NAME = "-*-*-*-*-*-*-%i-*-*-*-*-*-*-*";
+
+static XFontSet
+zvt_term_get_xfontset_internal (ZvtTerm *term,
+				const char *fontset_name,
+				int *new_charwidth, 
+				int *new_charheight,
+				int *new_fontascent)
+{
+  gint  missing_charset_count;
+  gchar **missing_charset_list;
+  gchar *def_string;
+  XFontSet new_fontset = 0;
+
+  new_fontset = XCreateFontSet (GDK_DISPLAY (), fontset_name,
+				&missing_charset_list,
+				&missing_charset_count,
+				&def_string);
+  if (missing_charset_list != NULL) {
+    XFreeStringList(missing_charset_list);
+    missing_charset_list = NULL;
+  }
+
+  if (new_fontset) {
+    XFontStruct **xfsList = 0;
+    char **fontnameList;
+    gint i;
+    gint max_percharwidth = 0;
+    gint max_percharheight = 0;
+    XRectangle extent;
+    gchar *bufp = (gchar*)ASCII_CHARACTERS;
+    gint char_len = strlen(bufp);
+
+    /* should be a little faster than using XmbTextPerCharExtents... */
+    for (i = 0; i < char_len; i++) {
+      if (XmbTextExtents(new_fontset, bufp++, 1,
+			 0, &extent) > 0) {
+	max_percharwidth = (extent.width > max_percharwidth ?
+			    extent.width : max_percharwidth);
+	max_percharheight = (extent.height > max_percharheight ?
+			     extent.height : max_percharheight);
+      }
+    }
+    *new_charwidth = max_percharwidth;
+    *new_charheight = max_percharheight;
+
+    XFontsOfFontSet (new_fontset, &xfsList, &fontnameList);
+    if (xfsList && xfsList[0])
+      *new_fontascent = xfsList[0]->ascent;
+
+    if (*new_charwidth == 0 || *new_charheight == 0 ||
+	*new_fontascent == 0) {
+      if (new_fontset)
+	XFreeFontSet (GDK_DISPLAY(), new_fontset);
+      new_fontset = 0;
+    }
+  }
+  return new_fontset;
+}
+
+static void
+zvt_term_get_xfontset (ZvtTerm *term,
+		       const PangoFontDescription *font_desc)
+{
+  struct _zvtprivate *zp;
+  GtkWidget *widget;
+  gchar *fontset_name = 0;
+  XFontSet new_fontset = 0;
+  int new_charwidth = 0;
+  int new_charheight = 0;
+  int new_fontascent = 0;
+
+  zp = _ZVT_PRIVATE (term);
+  widget = GTK_WIDGET (term);
+
+  fontset_name = xlfd_from_pango_font_description(GTK_WIDGET(widget),
+						  font_desc);
+  if (fontset_name) {
+    new_fontset = zvt_term_get_xfontset_internal (term, fontset_name, 
+						  &new_charwidth,
+						  &new_charheight,
+						  &new_fontascent);
+    g_free(fontset_name);
+  }
+
+  if (new_fontset == 0 || new_charwidth == 0 || new_charheight == 0) {
+    guint font_size = pango_font_description_get_size(font_desc)/PANGO_SCALE;
+    g_warning ("Cannot get required fonts from \"%s %i\"",
+	       pango_font_description_get_family (font_desc),
+	       font_size);
+
+    fontset_name = g_strdup_printf (DEFAULT_XLFD_NAME, font_size);
+    g_warning ("Use \"%s\" XLFD fontname - some characters may not appear correctly\n", fontset_name);
+
+    new_fontset = zvt_term_get_xfontset_internal (term, fontset_name,
+						  &new_charwidth,
+						  &new_charheight,
+						  &new_fontascent);
+    g_free (fontset_name);
+
+    if (new_fontset == 0 || new_charwidth == 0 || new_charheight == 0) {
+      fontset_name = g_strdup_printf (DEFAULT_XLFD_NAME, 0);
+      g_warning ("Use \"%s\" XLFD fontname - some characters may not appear correctly\n", fontset_name);
+      new_fontset = zvt_term_get_xfontset_internal (term, fontset_name,
+						    &new_charwidth,
+						    &new_charheight,
+						    &new_fontascent);
+      g_free (fontset_name);
+    }
+  }
+  g_return_if_fail (new_fontset != NULL);
+  g_return_if_fail (new_charwidth != 0);
+  g_return_if_fail (new_charheight != 0);
+  g_return_if_fail (new_fontascent!= 0);
+
+  if (term->xfontset)
+    XFreeFontSet (GDK_DISPLAY(), term->xfontset);
+  term->xfontset = new_fontset;
+  term->charwidth = new_charwidth;
+  term->charheight = new_charheight;
+  term->font_ascent = new_fontascent;
+
+  return;
+}
+
+/**
+ * zvt_term_set_pango_font:
+ * @term: A &ZvtTerm widget.
+ * @font_desc: Pango Font used for regular text.
+ *
+ * Load pango font into the terminal.
+ * 
+ * These fonts should be the same size, otherwise it could get messy ...
+ */
+void
+zvt_term_set_pango_font (ZvtTerm *term,
+			 const PangoFontDescription *font_desc)
+{
+  PangoFontDescription *font_bold_desc;
+  PangoFontset *fontset;
+  PangoFontMetrics *metrics;
+  struct _zvtprivate *zp;
+
+  g_return_if_fail (term != NULL);
+  g_return_if_fail (ZVT_IS_TERM (term));
+  g_return_if_fail (font_desc != NULL);
+
+  zp = _ZVT_PRIVATE(term);
+
+  fontset = pango_context_load_fontset(gdk_pango_context_get(),
+				       font_desc, gtk_get_default_language());
+  metrics = pango_fontset_get_metrics(fontset);
+
+  gtk_widget_queue_resize (GTK_WIDGET (term));
+
+#ifdef USE_PANGO_LAYOUT
+  term->font_ascent = pango_font_metrics_get_ascent(metrics)/PANGO_SCALE;
+  term->charheight = (pango_font_metrics_get_ascent(metrics) +
+		      pango_font_metrics_get_decent(metrics))/PANGO_SCALE;
+  term->charwidth = pango_font_metrics_get_approximate_digit_width(metrics)/PANGO_SCALE;
+#else
+  zvt_term_get_xfontset (term, font_desc);
+#endif
+
+  if (term->xfontset == NULL ||
+      term->charwidth == 0 || term->charheight == 0) {
+    g_warning ("Failed to load any required font, so crash will occur.." "check X11 font pathes and etc/pangox.alias file\n");
+  }
+
+  if (zp->pango_font)
+    pango_font_description_free(zp->pango_font);
+  if (zp->pango_font_bold)
+    pango_font_description_free(zp->pango_font_bold);
+
+  zp->pango_font = pango_font_description_copy(font_desc);
+  font_bold_desc = pango_font_description_copy(font_desc);
+  pango_font_description_set_weight(font_bold_desc, PANGO_WEIGHT_BOLD);
+
+  zp->pango_font_bold = font_bold_desc;
+
+  return;
+
+}
+
+#endif /* HAS_I18N */
