(moduledir): Use ${libdir} instead of ${exec_prefix}/lib.
[m17n/m17n-lib.git] / example / medit.c
index fc5197b..fe6fad2 100644 (file)
@@ -1,5 +1,5 @@
-/* medit.c -- simple multilingual editor.
-   Copyright (C) 2003, 2004
+/* medit.c -- simple multilingual editor.              -*- coding: euc-jp; -*-
+   Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008
      National Institute of Advanced Industrial Science and Technology (AIST)
      Registration Number H15PRO112
 
 
    You should have received a copy of the GNU Lesser General Public
    License along with the m17n library; if not, write to the Free
-   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
    02111-1307, USA.  */
 
 /***en
-    @enpage medit edit multilingual text
+    @enpage m17n-edit edit multilingual text
 
-    @section medit-synopsis SYNOPSIS
+    @section m17n-edit-synopsis SYNOPSIS
 
-    medit [ XT-OPTION ...] [ OPTION ... ] FILE
+    m17n-edit [ XT-OPTION ...] [ OPTION ... ] FILE
 
-    @section medit-description DESCRIPTION
+    @section m17n-edit-description DESCRIPTION
 
     Display FILE on a window and allow users to edit it.
 
     </ul>
 
     This program is to demonstrate how to use the m17n GUI API.
-    Although medit directly uses the GUI API, the API is mainly for
-    toolkit libraries or to implement XOM (X Outout Method), not for
-    direct use from application programs.
+    Although m17n-edit directly uses the GUI API, the API is mainly
+    for toolkit libraries or to implement XOM (X Output Method), not
+    for direct use from application programs.
 */
 /***ja
-    @japage medit Â¿¸À¸ì¥Æ¥­¥¹¥È¤ÎÊÔ½¸
+    @japage m17n-edit Â¿¸À¸ì¥Æ¥­¥¹¥È¤ÎÊÔ½¸
 
-    @section medit-synopsis SYNOPSIS
+    @section m17n-edit-synopsis SYNOPSIS
 
-    medit [ XT-OPTION ...] [ OPTION ... ] FILE
+    m17n-edit [ XT-OPTION ...] [ OPTION ... ] FILE
 
-    @section medit-description DESCRIPTION
+    @section m17n-edit-description DESCRIPTION
 
     FILE ¤ò¥¦¥£¥ó¥É¥¦¤Ëɽ¼¨¤·¡¢¥æ¡¼¥¶¤¬ÊÔ½¸¤Ç¤­¤ë¤è¤¦¤Ë¤¹¤ë¡£
 
 
     </ul>
 
-    ¤³¤Î¥×¥í¥°¥é¥à¤Ï m17n GUI API ¤Î»È¤¤Êý¤ò¼¨¤¹¤â¤Î¤Ç¤¢¤ë¡£medit ¤Ïľ 
-    ÀÜ GUI API ¤ò»È¤Ã¤Æ¤¤¤ë¤¬¡¢¤³¤Î API ¤Ï¼ç¤Ë¥Ä¡¼¥ë¥­¥Ã¥È¥é¥¤¥Ö¥é¥ê¤ä
-    XOM (X Outout Method) ¤Î¼ÂÁõÍѤǤ¢¤ê¡¢¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¥×¥í¥°¥é ¥à
-    ¤«¤é¤ÎľÀܤÎÍøÍѤò°Õ¿Þ¤·¤Æ¤¤¤Ê¤¤¡£
+    ¤³¤Î¥×¥í¥°¥é¥à¤Ï m17n GUI API ¤Î»È¤¤Êý¤ò¼¨¤¹¤â¤Î¤Ç¤¢¤ë¡£m17n-edit
+    ¤ÏľÀÜ GUI API ¤ò»È¤Ã¤Æ¤¤¤ë¤¬¡¢¤³¤Î API ¤Ï¼ç¤Ë¥Ä¡¼¥ë¥­¥Ã¥È¥é¥¤¥Ö¥é
+    ¥ê¤äXOM (X Output Method) ¤Î¼ÂÁõÍѤǤ¢¤ê¡¢¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¥×¥í¥°¥é
+    ¥à¤«¤é¤ÎľÀܤÎÍøÍѤò°Õ¿Þ¤·¤Æ¤¤¤Ê¤¤¡£
 */
 
 #ifndef FOR_DOXYGEN
 #include <unistd.h>
 #include <libgen.h>
 #include <locale.h>
+#include <dlfcn.h>
+
+#ifdef HAVE_X11_XAW_COMMAND_H
 
 #include <X11/keysym.h>
 #include <X11/Xatom.h>
 #include <X11/Intrinsic.h>
 #include <X11/StringDefs.h>
 #include <X11/Shell.h>
+
+#include <m17n-gui.h>
+#include <m17n-misc.h>
+#include <m17n-X.h>
+
 #include <X11/Xaw/Command.h>
 #include <X11/Xaw/Box.h>
 #include <X11/Xaw/Form.h>
 #include <X11/Xaw/SmeLine.h>
 #include <X11/Xaw/MenuButton.h>
 
-#include <m17n-gui.h>
-#include <m17n-misc.h>
-#include <m17n-X.h>
-
-#define VERSION "1.0.1"
-
 /* Global variables.  */
 
 char *filename;
@@ -169,23 +171,37 @@ Pixmap CheckPixmap;
 MFrame *frame;
 MText *mt;
 int nchars;                    /* == mtext_len (mt) */
+int mt_modified;
 MDrawControl control, input_status_control;
 MTextProperty *selection;
 
+MSymbol Mword;
+
 MFace *face_default;
 MFace *face_xxx_large;
 MFace *face_box;
 MFace *face_courier, *face_helvetica, *face_times;
-MFace *face_dv_ttyogesh, *face_freesans, *face_freemono;
+MFace *face_dv_ttyogesh, *face_freesans, *face_freeserif, *face_freemono;
 MFace *face_default_fontset, *face_no_ctl_fontset;
 MFace *face_input_status;
 
+MSymbol Mcoding_compound_text;
+
 int logical_move = 1;          /* If 0, move cursor visually.  */
 
-MInputMethod **input_method_table;
+typedef struct {
+  int available;
+  MSymbol language, name;
+  MInputMethod *im;
+} InputMethodInfo;
+
+InputMethodInfo *input_method_table;
+
 int num_input_methods;
 int current_input_method = -1; /* i.e. none */
+int unicode_input_method = -1;
 int auto_input_method = 0;
+int saved_input_method = -3;
 MInputContext *current_input_context;
 
 struct FaceRec
@@ -209,6 +225,7 @@ struct FaceRec
     {"times", &face_times},
     {"dv-ttyogesh", &face_dv_ttyogesh},
     {"freesans", &face_freesans},
+    {"freeserif", &face_freeserif},
     {"freemono", &face_freemono},
 
     {"Menu Style", NULL},
@@ -241,7 +258,7 @@ struct LineInfo
 {
   int from;                    /* BOL position of the line.  */
   int to;                      /* BOL position of the next line.  */
-  int y0, y1;           /* Top and bottom Y position of the line.  */
+  int y0, y1;                  /* Top and bottom Y position of the line.  */
   int ascent;                  /* Height of the top Y position.  */
 };
 
@@ -324,8 +341,8 @@ update_top (int pos)
   top.from = info.line_from;
   top.to = info.line_to;
   top.y0 = 0;
-  top.y1 = info.this.height;
-  top.ascent = - info.this.y;
+  top.y1 = info.metrics.height;
+  top.ascent = - info.metrics.y;
 }
 
 
@@ -336,12 +353,8 @@ update_scroll_bar (int from, int to)
 {
   float top = (float) from / nchars;
   float shown = (float) (to - from) / nchars;
-  XtArgVal *l_top = (XtArgVal *) &top;
-  XtArgVal *l_shown = (XtArgVal *) &shown;
 
-  XtSetArg (arg[0], XtNtopOfThumb, *l_top);
-  XtSetArg (arg[1], XtNshown, *l_shown);
-  XtSetValues (SbarWidget, arg, 2);
+  XawScrollbarSetThumb (SbarWidget, top, shown);
 }
 
 
@@ -357,7 +370,7 @@ redraw (int y0, int y1, int clear, int scroll_bar)
   int sel_y0 = SELECTEDP () ? sel_start.y0 : 0;
   struct LineInfo *line;
   
-  if (clear)
+  if (clear || control.anti_alias)
     CLEAR_AREA (0, y0, win_width, y1 - y0);
 
   /* Find a line closest to y0.  It is a cursor line if the cursor is
@@ -372,21 +385,26 @@ redraw (int y0, int y1, int clear, int scroll_bar)
 
   from = line->from;
   y = line->y0;
-  info.this.height = line->y1 - y;
-  info.this.y = - line->ascent;
+  info.metrics.height = line->y1 - y;
+  info.metrics.y = - line->ascent;
   info.line_to = line->to;
-  while (from < nchars && y + info.this.height <= y0)
+  while (y + info.metrics.height <= y0)
     {
-      y += info.this.height;
+      y += info.metrics.height;
       from = info.line_to;
+      if (from >= nchars)
+       break;
       GLYPH_INFO (from, from, info);
     }
-  y0 = y - info.this.y;
+  if (y + info.metrics.height <= y0)
+    return;
+
+  y0 = y - info.metrics.y;
   to = from;
   while (to < nchars && y < y1)
     {
       GLYPH_INFO (to, to, info);
-      y += info.this.height;
+      y += info.metrics.height;
       to = info.line_to;
     }
   if (to == nchars)
@@ -398,10 +416,10 @@ redraw (int y0, int y1, int clear, int scroll_bar)
       while (to < nchars)
        {
          GLYPH_INFO (to, to, info);
-         if (y + info.this.height >= win_height)
+         if (y + info.metrics.height >= win_height)
            break;
          to = info.line_to;
-         y += info.this.height;
+         y += info.metrics.height;
        }
       update_scroll_bar (top.from, to);
     }
@@ -415,16 +433,19 @@ set_input_method_spot ()
   int x = cursor.x + (control.orientation_reversed ? win_width : 0);
   int pos = cursor.from > 0 ? cursor.from - 1 : 0;
   MFace *faces[256];
-  int n = mtext_get_prop_values (mt, pos, Mface, (void **) faces, 256);
+  int n = 0;
   int size = 0, ratio = 0, i;
 
-  for (i = n - 1; i >= 0; i--)
-    {
-      if (! size)
-       size = (int) mface_get_prop (faces[i], Msize);
-      if (! ratio)
-       ratio = (int) mface_get_prop (faces[i], Mratio);
-    }
+  if (nchars > 0)
+    n = mtext_get_prop_values (mt, pos, Mface, (void **) faces, 256);
+  if (n > 0)
+    for (i = n - 1; i >= 0; i--)
+      {
+       if (! size)
+         size = (int) mface_get_prop (faces[i], Msize);
+       if (! ratio)
+         ratio = (int) mface_get_prop (faces[i], Mratio);
+      }
   if (! size)
     size = default_font_size;
   if (ratio)
@@ -448,12 +469,12 @@ redraw_cursor (int clear)
       MDrawMetric rect;
       int y0 = cur.y0, y1 = cur.y1;
 
-      if (beg != cur.from)
+      if (beg < cur.from)
        {
          TEXT_EXTENTS (beg, cur.from, rect);
          y0 -= rect.height;
        }
-      if (end != cur.to)
+      if (end > cur.to)
        {
          TEXT_EXTENTS (cur.to, end, rect);
          y1 += rect.height; 
@@ -467,8 +488,8 @@ redraw_cursor (int clear)
          int x = cursor.x;
 
          if (control.orientation_reversed)
-           x += win_width - cursor.this.width;
-         CLEAR_AREA (x, cur.y0, cursor.this.width, cursor.this.height);
+           x += win_width - cursor.logical_width;
+         CLEAR_AREA (x, cur.y0, cursor.logical_width, cursor.metrics.height);
        }
       DRAW_TEXT (cursor.x, cur.y0 + cur.ascent, cursor.from, cursor.to);
     }
@@ -477,18 +498,19 @@ redraw_cursor (int clear)
 
 /* Update the information about the location of cursor to the position
    $POS.  If $FULL is nonzero, update the information fully only from
-   the information about the top line.  Otherwise, truct the current
+   the information about the top line.  Otherwise, trust the current
    information in the structure $CUR.  */
 void
 update_cursor (int pos, int full)
 {
   MDrawMetric rect;
 
+  control.cursor_pos = pos;
   if (full)
     {
       /* CUR is inaccurate.  We can trust only TOP.  */
       GLYPH_INFO (top.from, pos, cursor);
-      cur.y0 = top.ascent + cursor.y + cursor.this.y;
+      cur.y0 = top.ascent + cursor.y + cursor.metrics.y;
     }
   else if (pos < cur.from)
     {
@@ -496,7 +518,7 @@ update_cursor (int pos, int full)
 
       TEXT_EXTENTS (from, cur.from, rect);
       GLYPH_INFO (from, pos, cursor);
-      cur.y0 -= (rect.height + rect.y) - (cursor.y + cursor.this.y);
+      cur.y0 -= (rect.height + rect.y) - (cursor.y + cursor.metrics.y);
     }
   else if (pos < cur.to)
     {
@@ -505,13 +527,13 @@ update_cursor (int pos, int full)
   else
     {
       GLYPH_INFO (cur.from, pos, cursor);
-      cur.y0 += cur.ascent + cursor.y + cursor.this.y;
+      cur.y0 += cur.ascent + cursor.y + cursor.metrics.y;
     }
 
   cur.from = cursor.line_from;
   cur.to = cursor.line_to;
-  cur.y1 = cur.y0 + cursor.this.height;
-  cur.ascent = - cursor.this.y;
+  cur.y1 = cur.y0 + cursor.metrics.height;
+  cur.ascent = - cursor.metrics.y;
 }
 
 
@@ -537,34 +559,28 @@ update_selection ()
       sel_start.ascent = - rect.y;
       GLYPH_INFO (pos, from, info);
       if (pos < info.line_from)
-       sel_start.y0 += - rect.y + info.y + info.this.y;
+       sel_start.y0 += - rect.y + info.y + info.metrics.y;
     }
   else
     {
       GLYPH_INFO (top.from, from, info);
-      sel_start.y0 = top.ascent + info.y + info.this.y;
+      sel_start.y0 = top.ascent + info.y + info.metrics.y;
     }
-  sel_start.ascent = -info.this.y;
-  sel_start.y1 = sel_start.y0 + info.this.height;
+  sel_start.ascent = -info.metrics.y;
+  sel_start.y1 = sel_start.y0 + info.metrics.height;
   sel_start.from = info.line_from;
   sel_start.to = info.line_to;
 
   if (to <= sel_start.to)
     {
       sel_end = sel_start;
-      if (to >= sel_end.to)
-       {
-         GLYPH_INFO (sel_start.from, to, info);
-         sel_end.y1 = sel_end.y0 + info.y + info.this.height;
-         sel_end.to = info.line_to;
-       }
     }
   else
     {
       GLYPH_INFO (sel_start.from, to, info);
-      sel_end.y0 = sel_start.y0 + sel_start.ascent + info.y + info.this.y;
-      sel_end.y1 = sel_end.y0 + info.this.height;
-      sel_end.ascent = - info.this.y;
+      sel_end.y0 = sel_start.y0 + sel_start.ascent + info.y + info.metrics.y;
+      sel_end.y1 = sel_end.y0 + info.metrics.height;
+      sel_end.ascent = - info.metrics.y;
       sel_end.from = info.line_from;
       sel_end.to = info.line_to;
     }
@@ -648,53 +664,101 @@ static void MenuHelpProc (Widget, XEvent *, String *, Cardinal *);
 void
 select_input_method (idx)
 {
+  int previous_input_method = current_input_method;
+
   if (idx == current_input_method)
     return;
-  if (current_input_context)
+  if (current_input_method >= 0)
     {
       minput_destroy_ic (current_input_context);
       current_input_context = NULL;
       current_input_method = -1;
     }
-  if (idx >= 0)
+
+  if (idx >= 0
+      && input_method_table[idx].available >= 0)
     {
-      MInputMethod *im = input_method_table[idx];
+      InputMethodInfo *im = input_method_table + idx;
 
-      if (im->language == Mnil)
+      if (im->available == 0)
        {
-         MInputXIMArgIC arg_xic;
-         Window win = XtWindow (TextWidget);
-
-         arg_xic.input_style = 0;
-         arg_xic.client_win = arg_xic.focus_win = win;
-         arg_xic.preedit_attrs =  arg_xic.status_attrs = NULL;
-         current_input_context = minput_create_ic (im, &arg_xic);
+         if (im->language)
+           im->im = minput_open_im (im->language, im->name, NULL);
+         else
+           {
+             MInputXIMArgIM arg_xim;
+
+             arg_xim.display = display;
+             arg_xim.db = NULL;  
+             arg_xim.res_name = arg_xim.res_class = NULL;
+             arg_xim.locale = NULL;
+             arg_xim.modifier_list = NULL;
+             im->im = minput_open_im (Mnil, im->name, &arg_xim);
+           }
+         im->available = im->im ? 1 : -1;
        }
-      else
+      if (im->im)
        {
-         MInputGUIArgIC arg_ic;
+         if (im->language == Mnil)
+           {
+             MInputXIMArgIC arg_xic;
+             Window win = XtWindow (TextWidget);
 
-         arg_ic.frame = frame;
-         arg_ic.client = (MDrawWindow) XtWindow (ShellWidget);
-         arg_ic.focus = (MDrawWindow) XtWindow (TextWidget);
-         current_input_context = minput_create_ic (im, &arg_ic);
-       }
+             arg_xic.input_style = 0;
+             arg_xic.client_win = arg_xic.focus_win = win;
+             arg_xic.preedit_attrs =  arg_xic.status_attrs = NULL;
+             current_input_context = minput_create_ic (im->im, &arg_xic);
+           }
+         else
+           {
+             MInputGUIArgIC arg_ic;
 
-      if (current_input_context)
-       {
-         set_input_method_spot ();
-         current_input_method = idx;
+             arg_ic.frame = frame;
+             arg_ic.client = (MDrawWindow) XtWindow (ShellWidget);
+             arg_ic.focus = (MDrawWindow) XtWindow (TextWidget);
+             current_input_context = minput_create_ic (im->im, &arg_ic);
+           }
+
+         if (current_input_context)
+           {
+             current_input_method = idx;
+             set_input_method_spot ();
+           }
+         else
+           {
+             minput_close_im (im->im);
+             im->im = NULL;
+             im->available = -1;
+             current_input_method = -1;
+           }
        }
     }
+  if (! auto_input_method)
+    {
+      XtSetArg (arg[0], XtNleftBitmap, None);
+      if (previous_input_method >= 0)
+       XtSetValues (InputMethodMenus[previous_input_method + 2], arg, 1);
+      else
+       XtSetValues (InputMethodMenus[0], arg, 1);
+      XtSetArg (arg[0], XtNleftBitmap, CheckPixmap);
+      if (current_input_method >= 0)
+       XtSetValues (InputMethodMenus[current_input_method + 2], arg, 1);
+      else
+       XtSetValues (InputMethodMenus[0], arg, 1);
+    }
+
   if (current_input_method >= 0)
     {
       char *label;
+
       XtSetArg (arg[0], XtNlabel, &label);
       XtGetValues (InputMethodMenus[current_input_method + 2], arg, 1);
       XtSetArg (arg[0], XtNlabel, label);
     }
   else
-    XtSetArg (arg[0], XtNlabel, "");
+    {
+      XtSetArg (arg[0], XtNlabel, "");
+    }
   XtSetValues (CurIMLang, arg, 1);
 }
 
@@ -708,6 +772,9 @@ static void MenuHelpProc (Widget w, XEvent *event, String *str, Cardinal *num);
 Boolean
 show_cursor (XtPointer client_data)
 {
+  MFaceHLineProp *hline;
+  MFaceBoxProp *box;
+
   if (cur.y0 < 0)
     {
       reseat (cur.from);
@@ -728,68 +795,65 @@ show_cursor (XtPointer client_data)
   if (current_input_context)
     set_input_method_spot ();
 
-  {
-    int pos = (SELECTEDP () ? mtext_property_start (selection)
-              : cursor.from > 0 ? cursor.from - 1
-              : cursor.from);
-    MFace *face = mface ();
-    MTextProperty *props[256];
-    int n = mtext_get_properties (mt, pos, Mface, props, 256);
-    int i;
-    char buf[256], *p = buf;
-    MSymbol sym;
-
-    buf[0] = '\0';
-    if (cursor.font)
-      {
-       int size = (int) mfont_get_prop (cursor.font, Msize);
-       MSymbol family = mfont_get_prop (cursor.font, Mfamily);
-       MSymbol weight = mfont_get_prop (cursor.font, Mweight);
-       MSymbol style = mfont_get_prop (cursor.font, Mstyle);
-       MSymbol registry = mfont_get_prop (cursor.font, Mregistry);
-
-       sprintf (p, "%dpt", size / 10), p += strlen (p);
-       if (family)
-         strcat (p, ","), strcat (p, msymbol_name (family)), p += strlen (p);
-       if (weight)
-         strcat (p, ","), strcat (p, msymbol_name (weight)), p += strlen (p);
-       if (style)
-         strcat (p, ","), strcat (p, msymbol_name (style)), p += strlen (p);
-       if (registry)
-         strcat (p, ","), strcat (p, msymbol_name (registry)), p += strlen (p);
-       p += strlen (p);
-      }
+  if (nchars > 0)
+    {
+      int pos = (SELECTEDP () ? mtext_property_start (selection)
+                : cursor.from > 0 ? cursor.from - 1
+                : cursor.from);
+      MFace *face = mface ();
+      MTextProperty *props[256];
+      int n = mtext_get_properties (mt, pos, Mface, props, 256);
+      int i;
+      char buf[256], *p = buf;
+      MSymbol sym;
 
-    mface_merge (face, face_default);
-    for (i = 0; i < n; i++)
-      if (props[i] != selection)
-       mface_merge (face, (MFace *) mtext_property_value (props[i]));
-    sym = (MSymbol) mface_get_prop (face, Mforeground);
-    if (sym != Mnil)
-      strcat (p, ","), strcat (p, msymbol_name (sym)), p += strlen (p);
-    if ((MSymbol) mface_get_prop (face, Mvideomode) == Mreverse)
-      strcat (p, ",rev"), p += strlen (p);
-    if (mface_get_prop (face, Mhline))
-      strcat (p, ",ul"), p += strlen (p);
-    if (mface_get_prop (face, Mbox))
-      strcat (p, ",box"), p += strlen (p);
-    m17n_object_unref (face);
+      buf[0] = '\0';
+      if (cursor.font)
+       {
+         int size = (int) mfont_get_prop (cursor.font, Msize);
+         MSymbol family = mfont_get_prop (cursor.font, Mfamily);
+         MSymbol weight = mfont_get_prop (cursor.font, Mweight);
+         MSymbol style = mfont_get_prop (cursor.font, Mstyle);
+         MSymbol registry = mfont_get_prop (cursor.font, Mregistry);
+
+         sprintf (p, "%dpt", size / 10), p += strlen (p);
+         if (family)
+           strcat (p, ","), strcat (p, msymbol_name (family)), p += strlen (p);
+         if (weight)
+           strcat (p, ","), strcat (p, msymbol_name (weight)), p += strlen (p);
+         if (style)
+           strcat (p, ","), strcat (p, msymbol_name (style)), p += strlen (p);
+         if (registry)
+           strcat (p, ","), strcat (p, msymbol_name (registry)), p += strlen (p);
+         p += strlen (p);
+       }
 
-    XtSetArg (arg[0], XtNborderWidth, 1);
-    XtSetArg (arg[1], XtNlabel, buf);
-    XtSetValues (CurFaceWidget, arg, 2);
-  }
+      mface_merge (face, face_default);
+      for (i = 0; i < n; i++)
+       if (props[i] != selection)
+         mface_merge (face, (MFace *) mtext_property_value (props[i]));
+      sym = (MSymbol) mface_get_prop (face, Mforeground);
+      if (sym != Mnil)
+       strcat (p, ","), strcat (p, msymbol_name (sym)), p += strlen (p);
+      if ((MSymbol) mface_get_prop (face, Mvideomode) == Mreverse)
+       strcat (p, ",rev"), p += strlen (p);
+      hline = mface_get_prop (face, Mhline);
+      if (hline && hline->width > 0)
+       strcat (p, ",ul"), p += strlen (p);
+      box = mface_get_prop (face, Mbox);
+      if (box && box->width > 0)
+       strcat (p, ",box"), p += strlen (p);
+      m17n_object_unref (face);
+
+      XtSetArg (arg[0], XtNborderWidth, 1);
+      XtSetArg (arg[1], XtNlabel, buf);
+      XtSetValues (CurFaceWidget, arg, 2);
+    }
 
   if (control.cursor_pos < nchars)
     {
-      MSymbol sym = Mnil;
+      MSymbol sym = mtext_get_prop (mt, control.cursor_pos, Mlanguage);
 
-      if (control.cursor_pos > 0
-         && mtext_ref_char (mt, control.cursor_pos - 1) != '\n')
-       sym = mtext_get_prop (mt, control.cursor_pos - 1, Mlanguage);
-      if (sym == Mnil)
-       sym = mtext_get_prop (mt, control.cursor_pos, Mlanguage);
-    
       if (sym == Mnil)
        {
          XtSetArg (arg[0], XtNborderWidth, 0);
@@ -798,8 +862,8 @@ show_cursor (XtPointer client_data)
       else
        {
          XtSetArg (arg[0], XtNborderWidth, 1);
-         XtSetArg (arg[1], XtNlabel,
-                   msymbol_name (msymbol_get (sym, Mlanguage)));
+         sym = mlanguage_name (sym);
+         XtSetArg (arg[1], XtNlabel, msymbol_name (sym));
          XtSetValues (CurLangWidget, arg, 2);
        }
       XtSetValues (CurLangWidget, arg, 2);
@@ -813,7 +877,8 @@ show_cursor (XtPointer client_data)
              int i;
 
              for (i = 0; i < num_input_methods; i++)
-               if (input_method_table[i]->language == sym)
+               if (input_method_table[i].language == sym
+                   && input_method_table[i].available >= 0)
                  break;
              if (i < num_input_methods)
                select_input_method (i);
@@ -875,13 +940,16 @@ delete_char (int n)
 {
   MDrawMetric rect;
   MDrawGlyphInfo info;
-  int old_y1, new_y1;
+  int y0, old_y1, new_y1;
   int from, to;
+  int line_from = cursor.line_from;
 
   if (n > 0)
     from = cursor.from, to = from + n;
   else
     {
+      from = cursor.from + n;
+      to = cursor.from;
       if (cursor.from == cur.from)
        {
          /* We are at the beginning of line.  */
@@ -895,13 +963,6 @@ delete_char (int n)
              reseat (info.line_from);
            }
          update_cursor (pos, 1);
-         from = cursor.from;
-         to = cursor.to;
-       }
-      else
-       {
-         from = cursor.from - 1;
-         to = cursor.from;
        }
     }
 
@@ -910,11 +971,15 @@ delete_char (int n)
 
   /* Now delete a character.  */
   mtext_del (mt, from, to);
-  nchars--;
+  nchars -= to - from;
   if (from >= top.from && from < top.to)
     update_top (top.from);
   update_cursor (from, 1);
 
+  y0 = cur.y0;
+  if (line_from != cursor.line_from)
+    y0 -= 1;
+
   TEXT_EXTENTS (cur.from, bol (to, 1), rect);
   new_y1 = cur.y0 + rect.height;
 
@@ -929,6 +994,7 @@ insert_chars (MText *newtext)
   int n = mtext_len (newtext);
   MDrawMetric rect;
   int y0, old_y1, new_y1;
+  int line_from;
 
   if (SELECTEDP ())
     {
@@ -939,9 +1005,15 @@ insert_chars (MText *newtext)
     }
 
   y0 = cur.y0;
+  if (cursor.line_from > 0
+      && mtext_ref_char (mt, cursor.line_from - 1) != '\n')
+    y0 -= control.min_line_descent;
+
   TEXT_EXTENTS (cur.from, bol (cur.to - 1, 1), rect);
   old_y1 = y0 + rect.height;
 
+  line_from = cursor.line_from;
+
   /* Now insert chars.  */
   mtext_ins (mt, cursor.from, newtext);
   nchars += n;
@@ -957,8 +1029,60 @@ insert_chars (MText *newtext)
 }
 
 
-/* Convert the currently selected text to COMPOUND-TEXT.  It is called
-   when someone requests the current value of the selection.  */
+int
+word_constituent_p (int c)
+{
+  MSymbol category = (MSymbol) mchar_get_prop (c, Mcategory);
+  char *name = category != Mnil ? msymbol_name (category) : NULL;
+
+  return (name && (name[0] == 'L' || name[0] == 'M'));
+}
+
+
+void
+forward_word ()
+{
+  int pos = cursor.from;
+
+  while (pos < nchars && ! word_constituent_p (mtext_ref_char (mt, pos)))
+    pos++;
+  if (pos < nchars)
+    {
+      MTextProperty *prop = mtext_get_property (mt, pos, Mword);
+
+      if (prop)
+       pos = mtext_property_end (prop);
+      else
+       while (pos < nchars && word_constituent_p (mtext_ref_char (mt, pos)))
+         pos++;
+    }
+  update_cursor (pos, 0);
+}
+
+void
+backward_word ()
+{
+  int pos = cursor.from;
+
+  while (pos > 0 && ! word_constituent_p (mtext_ref_char (mt, pos - 1)))
+    pos--;
+  if (pos > 0)
+    {
+      MTextProperty *prop = mtext_get_property (mt, pos - 1, Mword);
+
+      if (prop)
+       pos = mtext_property_start (prop);
+      else
+       while (pos > 0 && word_constituent_p (mtext_ref_char (mt, pos - 1)))
+         pos--;
+    }
+  update_cursor (pos, 0);
+}
+
+
+/* Convert the currently selected text to UTF8-STRING or
+   COMPOUND-TEXT.  It is called when someone requests the current
+   value of the selection.  */
 Boolean
 covert_selection (Widget w, Atom *selection_atom,
                  Atom *target, Atom *return_type,
@@ -968,14 +1092,52 @@ covert_selection (Widget w, Atom *selection_atom,
   MText *this_mt = mtext ();
   int from = mtext_property_start (selection);
   int to = mtext_property_end (selection);
+  MSymbol coding;
+  int len;
 
   mtext_copy (this_mt, 0, mt, from, to);
-  *length = mconv_encode_buffer (msymbol ("compound-text"),
-                                this_mt, buf, 4096);
-  *return_type = XA_COMPOUND_TEXT;
+  if (*target == XA_TEXT)
+    {
+#ifdef X_HAVE_UTF8_STRING
+      coding = Mcoding_utf_8;
+      *return_type = XA_UTF8_STRING;
+#else
+      coding = Mcoding_compound_text;
+      *return_type = XA_COMPOUND_TEXT;
+#endif
+    }
+  else if (*target == XA_UTF8_STRING)
+    {
+      coding = Mcoding_utf_8;
+      *return_type = XA_UTF8_STRING;
+    }
+  else if (*target == XA_STRING)
+    {
+      int i;
+
+      len = to - from;
+      for (i = 0; i < len; i++)
+       if (mtext_ref_char (this_mt, i) >= 0x100)
+         /* Can't encode in XA_STRING */
+         return False;
+      coding = Mcoding_iso_8859_1;
+      *return_type = XA_STRING;
+    }
+  else if (*target == XA_COMPOUND_TEXT)
+    {
+      coding = Mcoding_compound_text;
+      *return_type = XA_COMPOUND_TEXT;
+    }
+  else
+    return False;
+
+  len = mconv_encode_buffer (coding, this_mt, buf, 4096);
+  m17n_object_unref (this_mt);
+  if (len < 0)
+    return False;
+  *length = len;
   *value = (XtPointer) buf;
   *format = 8;
-  m17n_object_unref (this_mt);
   return True;
 }
 
@@ -1004,12 +1166,20 @@ get_selection (Widget w, XtPointer cliend_data, Atom *selection,  Atom *type,
     coding = Mnil;
   else if (*type == XA_COMPOUND_TEXT)
     coding = msymbol ("compound-text");
+#ifdef X_HAVE_UTF8_STRING
   else if (*type == XA_UTF8_STRING)
     coding = msymbol ("utf-8");
+#endif
   else
     goto err;
 
   this_mt = mconv_decode_buffer (coding, (unsigned char *) value, *length);
+  if (! this_mt && *type != XA_UTF8_STRING)
+    {
+      XtGetSelectionValue (w, XA_PRIMARY, XA_UTF8_STRING, get_selection, NULL,
+                          CurrentTime);
+      goto err;
+    }
   if (this_mt)
     {
       hide_cursor ();
@@ -1053,6 +1223,13 @@ ExposeProc (Widget w, XEvent *event, String *str, Cardinal *num)
       update_top (0);
       update_cursor (0, 1);
       redraw (0, win_height, 0, 1);
+      if (current_input_method >= 0)
+       {
+         int idx = current_input_method;
+
+         current_input_method = -1;
+         select_input_method (idx);
+       }
       show_cursor (NULL);
     }
   else
@@ -1097,6 +1274,20 @@ ButtonProc (Widget w, XEvent *event, String *str, Cardinal *num)
       redraw (sel_start.y0, sel_end.y1, 1, 0);
     }
   hide_cursor ();
+  if (current_input_context
+      && minput_filter (current_input_context, Minput_focus_move, NULL) == 0)
+    {
+      MText *produced = mtext ();
+
+      minput_lookup (current_input_context, Mnil, NULL, produced);
+      if (mtext_len (produced) > 0)
+       {
+         insert_chars (produced);
+         if (pos >= cursor.from)
+           pos += mtext_len (produced);
+       }
+      m17n_object_unref (produced);
+    }
   update_cursor (pos, 0);
 }
 
@@ -1241,6 +1432,42 @@ ButtonMoveProc (Widget w, XEvent *event, String *str, Cardinal *num)
 }
 
 void
+FocusInProc (Widget w, XEvent *event, String *str, Cardinal *num)
+{
+  if (current_input_context
+      && minput_filter (current_input_context, Minput_focus_in, NULL) == 0)
+    {
+      MText *produced = mtext ();
+
+      minput_lookup (current_input_context, Mnil, NULL, produced);
+      if (mtext_len (produced) > 0)
+       {
+         hide_cursor ();
+         insert_chars (produced);
+       }
+      m17n_object_unref (produced);
+    }
+}
+
+void
+FocusOutProc (Widget w, XEvent *event, String *str, Cardinal *num)
+{
+  if (current_input_context
+      && minput_filter (current_input_context, Minput_focus_out, NULL) == 0)
+    {
+      MText *produced = mtext ();
+
+      minput_lookup (current_input_context, Mnil, NULL, produced);
+      if (mtext_len (produced) > 0)
+       {
+         hide_cursor ();
+         insert_chars (produced);
+       }
+      m17n_object_unref (produced);
+    }
+}
+
+void
 ScrollProc (Widget w, XtPointer client_data, XtPointer position)
 {
   int from;
@@ -1259,9 +1486,9 @@ ScrollProc (Widget w, XtPointer client_data, XtPointer position)
        {
          pos = bol (from - 1, 0);
          GLYPH_INFO (pos, from - 1, info);
-         if (height + info.this.height > win_height)
+         if (height + info.metrics.height > win_height)
            break;
-         height += info.this.height;
+         height += info.metrics.height;
          from = info.line_from;
        }
       if (cursor_pos >= top.to)
@@ -1271,9 +1498,9 @@ ScrollProc (Widget w, XtPointer client_data, XtPointer position)
          while (cursor_pos < nchars)
            {
              GLYPH_INFO (pos, pos, info);
-             if (height + info.this.height > win_height)
+             if (height + info.metrics.height > win_height)
                break;
-             height += info.this.height;
+             height += info.metrics.height;
              cursor_pos = pos;
              pos = info.line_to;
            }
@@ -1287,10 +1514,10 @@ ScrollProc (Widget w, XtPointer client_data, XtPointer position)
       while (from < nchars)
        {
          GLYPH_INFO (from, from, info);
-         if (height + info.this.height > win_height
+         if (height + info.metrics.height > win_height
              || info.line_to >= nchars)
            break;
-         height += info.this.height;
+         height += info.metrics.height;
          from = info.line_to;
        }
       if (from == nchars)
@@ -1321,6 +1548,7 @@ JumpProc (Widget w, XtPointer client_data, XtPointer persent_ptr)
   update_cursor (pos1, 1);
 }
 
+static void InputMethodProc (Widget, XtPointer, XtPointer);
 
 static void
 KeyProc (Widget w, XEvent *event, String *str, Cardinal *num)
@@ -1332,15 +1560,26 @@ KeyProc (Widget w, XEvent *event, String *str, Cardinal *num)
   /* If set to 1, do not update target_x_position.  */
   int keep_target_x_position = 0;
   MText *produced;
+  int y0, old_y1, new_y1;
 
+  hide_cursor ();
+
+  mt_modified = 0;
+  y0 = cur.y0;
+  old_y1 = cur.y1;
   if (current_input_context
       && minput_filter (current_input_context, Mnil, event))
-    return;
+    {
+      if (mt_modified)
+       {
+         new_y1 = cur.y1;
+         update_region (y0, old_y1, new_y1);
+       }
+      return;
+    }
   if (event->type == KeyRelease)
     return;
 
-  hide_cursor ();
-
   produced = mtext ();
   ret = minput_lookup (current_input_context, Mnil, event, produced);
   if (mtext_len (produced) > 0)
@@ -1349,6 +1588,12 @@ KeyProc (Widget w, XEvent *event, String *str, Cardinal *num)
     ret = XLookupString (key_event, buf, sizeof (buf), &keysym, NULL);
   m17n_object_unref (produced);
 
+  if (saved_input_method > -3)
+    {
+      InputMethodProc (w, (XtPointer) saved_input_method, NULL);
+      saved_input_method = -3;
+    }
+
   switch (keysym)
     {
     case XK_Delete:
@@ -1488,6 +1733,22 @@ KeyProc (Widget w, XEvent *event, String *str, Cardinal *num)
        ScrollProc (w, NULL, (XtPointer) -1);
       break;
 
+    case XK_b:
+      if (key_event->state >= Mod1Mask)
+       {
+         lose_selection (NULL, NULL);
+         backward_word ();
+         break;
+       }
+
+    case XK_f:
+      if (key_event->state >= Mod1Mask)
+       {
+         lose_selection (NULL, NULL);
+         forward_word ();
+         break;
+       }
+
     default:
       if (ret > 0)
        {
@@ -1501,11 +1762,20 @@ KeyProc (Widget w, XEvent *event, String *str, Cardinal *num)
              redraw (0, win_height, 1, 1);
              return;
            }
+         else if (buf[0] == '='
+                  && (event->xkey.state & ControlMask)
+                  && unicode_input_method >= 0)
+           {
+             saved_input_method = current_input_method;
+             InputMethodProc (w, (XtPointer) unicode_input_method, NULL);
+             minput_filter (current_input_context, msymbol ("C-u"), NULL);
+           }
          else
            {
              MText *temp = mtext ();
 
-             mtext_cat_char (temp, buf[0] == '\r' ? '\n' : buf[0]);
+             mtext_cat_char (temp, buf[0] == '\r' ? '\n'
+                             : ((unsigned char *) buf)[0]);
              if (current_input_context)
                mtext_put_prop (temp, 0, 1, Mlanguage,
                                current_input_context->im->language);
@@ -1546,7 +1816,7 @@ SaveProc (Widget w, XtPointer client_data, XtPointer call_data)
       mtext_detach_property (selection);
     }
 
-  mconv_encode_stream (Mcoding_utf_8, mt, fp);
+  mconv_encode_stream (Mcoding_utf_8_full, mt, fp);
   fclose (fp);
   if (from >= 0)
     select_region (from, to);
@@ -1597,7 +1867,7 @@ read_file ()
 
   if (! fp)
     FATAL_ERROR ("Can't read \"%s\"!\n", filename);
-  mt = mconv_decode_stream (Mcoding_utf_8, fp);
+  mt = mconv_decode_stream (Mcoding_utf_8_full, fp);
   fclose (fp);
   if (! mt)
     FATAL_ERROR ("Can't decode \"%s\" by UTF-8!\n", filename);
@@ -1633,8 +1903,6 @@ BidiProc (Widget w, XtPointer client_data, XtPointer call_data)
   redraw (0, win_height, 1, 0);
 }
 
-extern int line_break (MText *mt, int pos, int from, int to, int line, int y);
-
 void
 LineBreakProc (Widget w, XtPointer client_data, XtPointer call_data)
 {
@@ -1646,7 +1914,7 @@ LineBreakProc (Widget w, XtPointer client_data, XtPointer call_data)
   else
     {
       control.max_line_width = win_width;
-      control.line_break = (data == 1 ? NULL : line_break);
+      control.line_break = (data == 1 ? NULL : mdraw_default_line_break);
     }
   for (i = 0; i < 3; i++)
     {
@@ -1662,6 +1930,25 @@ LineBreakProc (Widget w, XtPointer client_data, XtPointer call_data)
 }
 
 void
+FilterProc (Widget w, XtPointer client_data, XtPointer call_data)
+{
+  char *filter_module = (char *) client_data;
+  void *handle;
+  void (*func) (MText *, int, int);
+
+  if (! SELECTEDP ())
+    return;
+  handle = dlopen (filter_module, RTLD_NOW);
+  if (! handle)
+    return;
+  func = (void (*) (MText *, int, int)) dlsym (handle, "filter");
+  if (func)
+    (*func) (mt, mtext_property_start (selection),
+            mtext_property_end (selection));
+  dlclose (handle);
+}
+
+void
 CursorProc (Widget w, XtPointer client_data, XtPointer call_data)
 {
   int data = (int) client_data;
@@ -1700,6 +1987,7 @@ CursorProc (Widget w, XtPointer client_data, XtPointer call_data)
       XtSetValues (CursorMenus[i], arg, 1);
     }
 
+  update_cursor (cursor.from, 0);
   redraw (0, win_height, 1, 0);
 }
 
@@ -1708,33 +1996,37 @@ InputMethodProc (Widget w, XtPointer client_data, XtPointer call_data)
 {
   int idx = (int) client_data;
 
-  if (idx == -2 ? current_input_method < 0
+  if (idx == -2 ? (! auto_input_method && current_input_method < 0)
       : idx == -1 ? auto_input_method
       : idx == current_input_method)
     return;
 
-  XtSetArg (arg[0], XtNleftBitmap, None);
   if (auto_input_method)
     {
+      select_input_method (-1);
+      XtSetArg (arg[0], XtNleftBitmap, None);
       XtSetValues (InputMethodMenus[1], arg, 1);
       auto_input_method = 0;
     }
-  else if (current_input_method < 0)
-    XtSetValues (InputMethodMenus[0], arg, 1);
-  else
-    XtSetValues (InputMethodMenus[current_input_method + 2], arg, 1);
 
   if (idx == -1)
     {
+      select_input_method (-1);
+      XtSetArg (arg[0], XtNleftBitmap, None);
+      XtSetValues (InputMethodMenus[0], arg, 1);
+      XtSetArg (arg[0], XtNleftBitmap, CheckPixmap);
+      XtSetValues (InputMethodMenus[1], arg, 1);
       auto_input_method = 1;
       hide_cursor ();
     }
   else
-    select_input_method (idx);
-  XtSetArg (arg[0], XtNleftBitmap, CheckPixmap);
-  XtSetValues (InputMethodMenus[idx + 2], arg, 1);
+    {
+      select_input_method (idx);
+    }
 }
 
+MPlist *default_face_list;
+
 void
 FaceProc (Widget w, XtPointer client_data, XtPointer call_data)
 {
@@ -1742,8 +2034,37 @@ FaceProc (Widget w, XtPointer client_data, XtPointer call_data)
   int from, to;
   int old_y1;
 
+  hide_cursor ();
   if (! SELECTEDP ())
-    return;
+    {
+      MPlist *plist;
+
+      if (idx >= 0)
+       {
+         MFace *face = mframe_get_prop (frame, Mface);
+
+         for (plist = default_face_list; mplist_key (plist) != Mnil;
+              plist = mplist_next (plist)) 
+           mface_merge (face, mplist_value (plist));
+         mplist_add (plist, Mt, *face_table[idx].face);
+         mface_merge (face, *face_table[idx].face);
+       }
+      else if (mplist_key (mplist_next (default_face_list)) != Mnil)
+       {
+         MFace *face = mframe_get_prop (frame, Mface);
+
+         for (plist = default_face_list;
+              mplist_key (mplist_next (plist)) != Mnil;
+              plist = mplist_next (plist)) 
+           mface_merge (face, mplist_value (plist));
+         mplist_pop (plist);
+       }
+      update_top (0);
+      update_cursor (0, 1);
+      redraw (0, win_height, 1, 1);
+      show_cursor (NULL);
+      return;
+    }
 
   XtAppAddWorkProc (context, show_cursor, NULL);
   from = mtext_property_start (selection);
@@ -1838,7 +2159,7 @@ DumpImageProc (Widget w, XtPointer client_data, XtPointer call_data)
     mdump = popen ("mdump -q", "w");
   if (! mdump)
     return;
-  converter = mconv_stream_converter (Mcoding_utf_8, mdump);
+  converter = mconv_stream_converter (Mcoding_utf_8_full, mdump);
   mconv_encode_range (converter, mt, from, to);
   mconv_free_converter (converter);
   fclose (mdump);
@@ -1869,11 +2190,64 @@ input_status (MInputContext *ic, MSymbol command)
   XtSetValues (CurIMStatus, arg, 1);
 }
 
+void
+surrounding_text_handler (MInputContext *ic, MSymbol command)
+{
+  if (command == Minput_get_surrounding_text)
+    {
+      int len = (int) mplist_value (ic->plist);
+      int pos;
+      MText *surround;
+
+      if (len < 0)
+       {
+         pos = cursor.from + len;
+         if (pos < 0)
+           pos = 0;
+         surround = mtext_duplicate (mt, pos, cursor.from);
+       }
+      else if (len > 0)
+       {
+         pos = cursor.from + len;
+         if (pos > nchars)
+           pos = nchars;
+         surround = mtext_duplicate (mt, cursor.from, pos);
+       }
+      else
+       surround = mtext ();
+      mplist_set (ic->plist, Mtext, surround);
+      m17n_object_unref (surround);
+    }
+  else if (command == Minput_delete_surrounding_text)
+    {
+      int len = (int) mplist_value (ic->plist);      
+
+      if (len < 0)
+       {
+         if (cursor.from + len < 0)
+           len = - cursor.from;
+         mtext_del (mt, cursor.from + len, cursor.from);
+         nchars += len;
+         update_cursor (cursor.from + len, 1);
+       }
+      else if (len > 0)
+       {
+         if (cursor.from + len > nchars)
+           len = nchars - cursor.from;
+         mtext_del (mt, cursor.from, cursor.from + len);
+         nchars -= len;
+         update_cursor (cursor.from, 1);
+       }
+      if (len)
+       mt_modified = 1;
+    }
+}
+
 int
 compare_input_method (const void *elt1, const void *elt2)
 {
-  const MInputMethod *im1 = *(MInputMethod **) elt1;
-  const MInputMethod *im2 = *(MInputMethod **) elt2;
+  const InputMethodInfo *im1 = elt1;
+  const InputMethodInfo *im2 = elt2;
   MSymbol lang1, lang2;
 
   if (im1->language == Mnil)
@@ -1884,61 +2258,91 @@ compare_input_method (const void *elt1, const void *elt2)
     return 1;
   if (im2->language == Mt)
     return -1;
-  lang1 = msymbol_get (im1->language, Mlanguage);
-  lang2 = msymbol_get (im2->language, Mlanguage);
+  lang1 = mlanguage_name (im1->language);
+  lang2 = mlanguage_name (im2->language);
   return strcmp (msymbol_name (lang1), msymbol_name (lang2));
 }
 
 void
-setup_input_methods (int with_xim)
+setup_input_methods (int with_xim, char *initial_input_method)
 {
-  MInputMethod *im = NULL;
-  MInputXIMArgIM arg_xim;
   MPlist *plist = mdatabase_list (msymbol ("input-method"), Mnil, Mnil, Mnil);
   MPlist *pl;
-  int i = 0;
-
-  num_input_methods = mplist_length (plist);
+  int i;
+  MSymbol Municode = msymbol ("unicode");
 
+  num_input_methods = plist ? mplist_length (plist) : 0;
   if (with_xim)
-    {
-      arg_xim.display = display;
-      arg_xim.db = NULL;  
-      arg_xim.res_name = arg_xim.res_class = NULL;
-      arg_xim.locale = NULL;
-      arg_xim.modifier_list = NULL;
-      im = minput_open_im (Mnil, msymbol ("xim"), &arg_xim);
-      if (im)
-       num_input_methods++;
-    }
-  input_method_table = calloc (num_input_methods, sizeof (MInputMethod *));
-  if (im)
-    input_method_table[i++] = im;
-  for (pl = plist; mplist_key (pl) != Mnil; pl = mplist_next (pl))
-    {
-      MDatabase *mdb = mplist_value (pl);
-      MSymbol *tag = mdatabase_tag (mdb);
+    num_input_methods++;
+  input_method_table = calloc (num_input_methods, sizeof (InputMethodInfo));
 
-      if (tag[1] != Mnil)
+  i = 0;
+  if (plist)
+    {
+      for (pl = plist; mplist_key (pl) != Mnil; pl = mplist_next (pl), i++)
        {
-         im = minput_open_im (tag[1], tag[2], NULL);
-         if (im)
-           input_method_table[i++] = im;
+         MDatabase *mdb = mplist_value (pl);
+         MSymbol *tag = mdatabase_tag (mdb);
+
+         if (tag[2] == Mnil)
+           i--, num_input_methods--;
+         else
+           {
+             input_method_table[i].language = tag[1];
+             input_method_table[i].name = tag[2];
+           }
        }
+      m17n_object_unref (plist);
+    }
+  if (with_xim)
+    {
+      input_method_table[i].language = Mnil;
+      input_method_table[i].name = msymbol ("xim");
+      i++;
     }
 
-  m17n_object_unref (plist);
-  num_input_methods = i;
   qsort (input_method_table, num_input_methods, sizeof input_method_table[0],
         compare_input_method);
+  for (i = 0; i < num_input_methods; i++)
+    if (input_method_table[i].language == Mt
+       && input_method_table[i].name == Municode)
+      {
+       unicode_input_method = i;
+       break;
+      }
+  mplist_put_func (minput_driver->callback_list, Minput_status_start,
+                  M17N_FUNC (input_status));
+  mplist_put_func (minput_driver->callback_list, Minput_status_draw,
+                  M17N_FUNC (input_status));
+  mplist_put_func (minput_driver->callback_list, Minput_status_done,
+                  M17N_FUNC (input_status));
+  mplist_put_func (minput_driver->callback_list, Minput_get_surrounding_text,
+                  M17N_FUNC (surrounding_text_handler));
+  mplist_put_func (minput_driver->callback_list, Minput_delete_surrounding_text,
+                  M17N_FUNC (surrounding_text_handler));
+
   current_input_context = NULL;
+  current_input_method = -1;
+
+  if (initial_input_method)
+    {
+      char *lang_name, *method_name;
+      char *p = strchr (initial_input_method, '-');
+
+      if (p && p[1])
+       lang_name = initial_input_method, *p = '\0', method_name = p + 1;
+      else
+       lang_name = "t", method_name = initial_input_method;
 
-  mplist_put (minput_driver->callback_list, Minput_status_start,
-             (void *) input_status);
-  mplist_put (minput_driver->callback_list, Minput_status_draw,
-             (void *) input_status);
-  mplist_put (minput_driver->callback_list, Minput_status_done,
-             (void *) input_status);
+      for (i = 0; i < num_input_methods; i++)
+       if ((strcmp (method_name, msymbol_name (input_method_table[i].name))
+            == 0)
+           && (strcmp (lang_name, msymbol_name (input_method_table[i].language)) == 0))
+         {
+           current_input_method = i;
+           break;
+         }
+    }
 }
 
 
@@ -2040,7 +2444,7 @@ FileDialogProc (Widget w, XtPointer client_data, XtPointer call_data)
       m17n_object_unref (mt);
       if (fp)
        {
-         mt = mconv_decode_stream (Mcoding_utf_8, fp);
+         mt = mconv_decode_stream (Mcoding_utf_8_full, fp);
          fclose (fp);
          if (! mt)
            mt = mtext ();
@@ -2121,7 +2525,8 @@ create_menu_button (Widget top, Widget parent, Widget left, char *button_name,
   XtSetArg (arg[3], XtNhighlightThickness, 1);
   XtSetArg (arg[4], XtNleft, XawChainLeft);
   XtSetArg (arg[5], XtNright, XawChainLeft);
-  i = 6;
+  XtSetArg (arg[6], XtNinternational, True);
+  i = 7;
   if (left)
     XtSetArg (arg[i], XtNfromHoriz, left), i++;
   button = XtCreateManagedWidget (button_name, menuButtonWidgetClass, parent,
@@ -2179,7 +2584,9 @@ XtActionsRec actions[] = {
   {"ButtonRelease", ButtonReleaseProc},
   {"ButtonMotion", ButtonMoveProc},
   {"Button2Press", Button2Proc},
-  {"MenuHelp", MenuHelpProc}
+  {"MenuHelp", MenuHelpProc},
+  {"FocusIn", FocusInProc},
+  {"FocusOut", FocusOutProc}
 };
 
 
@@ -2199,8 +2606,14 @@ help_exit (char *prog, int exit_code)
   printf ("Display FILE on a window and allow users to edit it.\n");
   printf ("XT-OPTIONs are standard Xt arguments (e.g. -fn, -fg).\n");
   printf ("The following OPTIONs are available.\n");
+  printf ("  %-13s\n\t\t%s", "--fontset FONTSET",
+         "Use the specified fontset\n");
+  printf ("  %-13s %s", "-s SIZE", "Font size in 1/10 point (default 120).\n");
+  printf ("  %-13s\n\t\t%s", "--im INPUT-METHOD",
+         "Input method activated initially.\n");
   printf ("  %-13s %s", "--version", "print version number\n");
   printf ("  %-13s %s", "-h, --help", "print this message\n");
+         
   exit (exit_code);
 }
 
@@ -2209,6 +2622,9 @@ main (int argc, char **argv)
 {
   Widget form, BodyWidget, w;
   char *fontset_name = NULL;
+  char *font_name = NULL;
+  int fontsize = 0;
+  char *initial_input_method = NULL;
   int col = 80, row = 32;
   /* Translation table for TextWidget.  */
   String trans = "<Expose>: Expose()\n\
@@ -2221,7 +2637,9 @@ main (int argc, char **argv)
                  <Btn2Down>: Button2Press()";
   /* Translation table for the top form widget.  */
   String trans2 = "<Key>: Key()\n\
-                  <KeyUp>: Key()";
+                  <KeyUp>: Key()\n\
+                  <FocusIn>: FocusIn()\n\
+                  <FocusOut>: FocusOut()";
   String pop_face_trans
     = "<EnterWindow>: MenuHelp(Pop face property) highlight()\n\
        <LeaveWindow>: MenuHelp() reset()\n\
@@ -2235,11 +2653,13 @@ main (int argc, char **argv)
   int font_width, font_ascent, font_descent;
   int with_xim = 0;
   int i, j;
+  char *filter = NULL;
+  MFont *font = NULL;
 
   setlocale (LC_ALL, "");
   /* Create the top shell.  */
   XtSetLanguageProc (NULL, NULL, NULL);
-  ShellWidget = XtOpenApplication (&context, "MEdit", NULL, 0, &argc, argv,
+  ShellWidget = XtOpenApplication (&context, "M17NEdit", NULL, 0, &argc, argv,
                                   NULL, sessionShellWidgetClass, NULL, 0);
   display = XtDisplay (ShellWidget);
   screen = XScreenNumberOfScreen (XtScreen (ShellWidget));
@@ -2252,8 +2672,8 @@ main (int argc, char **argv)
        help_exit (argv[0], 0);
       else if (! strcmp (argv[i], "--version"))
        {
-         printf ("medit (m17n library) %s\n", VERSION);
-         printf ("Copyright (C) 2003 AIST, JAPAN\n");
+         printf ("m17n-edit (m17n library) %s\n", M17NLIB_VERSION_NAME);
+         printf ("Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 AIST, JAPAN\n");
          exit (0);
        }
       else if (! strcmp (argv[i], "--geometry"))
@@ -2262,44 +2682,70 @@ main (int argc, char **argv)
          if (sscanf (argv[i], "%dx%d", &col, &row) != 2)
            help_exit (argv[0], 1);
        }
+      else if (! strcmp (argv[i], "-s"))
+       {
+         i++;
+         fontsize = atoi (argv[i]);
+         if (fontsize < 0)
+           fontsize = 120;
+       }
       else if (! strcmp (argv[i], "--fontset"))
        {
          i++;
          fontset_name = strdup (argv[i]);
        }
+      else if (! strcmp (argv[i], "--font"))
+       {
+         i++;
+         font_name = strdup (argv[i]);
+       }
+      else if (! strcmp (argv[i], "--im"))
+       {
+         i++;
+         initial_input_method = strdup (argv[i]);
+       }
       else if (! strcmp (argv[i], "--with-xim"))
        {
          with_xim = 1;
        }
+      else if (! strcmp (argv[i], "--filter"))
+       {
+         i++;
+         filter = argv[i];
+       }
       else if (argv[i][0] != '-')
        {
          filename = strdup (argv[i]);
        }
       else
        {
-         fprintf (stderr, "Unknown option: %s", argv[i]);
+         fprintf (stderr, "Unknown option: %s\n", argv[i]);
          help_exit (argv[0], 1);
        }
     }
   if (! filename)
-    help_exit (argv[0], 1);
+    filename = strdup ("/dev/null");
 
   mdatabase_dir = ".";
   /* Initialize the m17n library.  */
   M17N_INIT ();
   if (merror_code != MERROR_NONE)
     FATAL_ERROR ("%s\n", "Fail to initialize the m17n library!");
+  minput_driver = &minput_gui_driver;
 
   mt = read_file (filename);
   serialized = 0;
 
   nchars = mtext_len (mt);
 
+  Mword = msymbol ("word");
+
   {
     MFace *face = mface ();
 
-    mface_put_prop (face, Mbackground, msymbol ("blue"));
-    mface_put_prop (face, Mforeground, msymbol ("yellow"));
+    mface_put_prop (face, Mforeground, msymbol ("blue"));
+    mface_put_prop (face, Mbackground, msymbol ("yellow"));
+    mface_put_prop (face, Mvideomode, Mreverse);
     selection = mtext_property (Mface, face, MTEXTPROP_NO_MERGE);
     m17n_object_unref (face);
   }
@@ -2310,25 +2756,48 @@ main (int argc, char **argv)
   XA_TEXT = XInternAtom (display, "TEXT", False);
   XA_COMPOUND_TEXT = XInternAtom (display, "COMPOUND_TEXT", False);
   XA_UTF8_STRING = XInternAtom (display, "UTF8_STRING", False);
+  Mcoding_compound_text = mconv_resolve_coding (msymbol ("compound-text"));
+  if (Mcoding_compound_text == Mnil)
+    FATAL_ERROR ("%s\n", "Don't know about COMPOUND-TEXT encoding!");
+
   {
     MPlist *plist = mplist ();
-    MFace *face;
     MFont *font;
 
     mplist_put (plist, msymbol ("widget"), ShellWidget);
-    if (fontset_name)
+    if (fontset_name || font_name || fontsize > 0)
       {
-       MFontset *fontset = mfontset (fontset_name);
-       
-       face = mface ();
-       mface_put_prop (face, Mfontset, fontset);
-       m17n_object_unref (fontset);
+       MFace *face;
+
+       if (font_name)
+         {
+           font = mfont_parse_name (font_name, Mnil);
+           if (font)
+             face = mface_from_font (font);
+           else
+             face = mface ();
+         }
+       else
+         face = mface ();
+       if (fontset_name)
+         {
+           MFontset *fontset = mfontset (fontset_name);
+
+           mface_put_prop (face, Mfontset, fontset);
+           m17n_object_unref (fontset);
+         }
+       if (fontsize > 0)
+         mface_put_prop (face, Msize, (void *) fontsize);
        mplist_add (plist, Mface, face);
        m17n_object_unref (face);
       }
     frame = mframe (plist);
+    if (! frame)
+      FATAL_ERROR ("%s\n", "Fail to create a frame!");
     m17n_object_unref (plist);
-    face_default = (MFace *) mframe_get_prop (frame, Mface);
+    face_default = mface_copy ((MFace *) mframe_get_prop (frame, Mface));
+    default_face_list = mplist ();
+    mplist_add (default_face_list, Mt, face_default);
     face_default_fontset = mface ();
     mface_put_prop (face_default_fontset, Mfontset,
                    mface_get_prop (face_default, Mfontset));
@@ -2366,6 +2835,8 @@ main (int argc, char **argv)
   mface_put_prop (face_dv_ttyogesh, Mfamily, msymbol ("dv-ttyogesh"));
   face_freesans = mface ();
   mface_put_prop (face_freesans, Mfamily, msymbol ("freesans"));
+  face_freeserif = mface ();
+  mface_put_prop (face_freeserif, Mfamily, msymbol ("freeserif"));
   face_freemono = mface ();
   mface_put_prop (face_freemono, Mfamily, msymbol ("freemono"));
 
@@ -2376,7 +2847,7 @@ main (int argc, char **argv)
     MFont *dev_font = mfont ();
     MFont *thai_font = mfont ();
     MFont *tib_font = mfont ();
-    MFontset *fontset;
+    MFontset *fontset, *fontset_no_ctl;
     MSymbol unicode_bmp = msymbol ("unicode-bmp");
     MSymbol no_ctl = msymbol ("no-ctl");
 
@@ -2387,25 +2858,27 @@ main (int argc, char **argv)
     mfont_put_prop (tib_font, Mfamily, msymbol ("mtib"));
     mfont_put_prop (tib_font, Mregistry, unicode_bmp);
 
-    fontset = mfontset_copy (mfontset (fontset_name), "no-ctl");
-    mfontset_modify_entry (fontset, msymbol ("latin"), Mnil, Mnil,
+    fontset = mfontset (fontset_name);
+    fontset_no_ctl = mfontset_copy (fontset, "no-ctl");
+    m17n_object_unref (fontset);
+    mfontset_modify_entry (fontset_no_ctl, msymbol ("latin"), Mnil, Mnil,
                           latin_font, Mnil, 0);
-    mfontset_modify_entry (fontset, msymbol ("devanagari"), Mnil, Mnil,
+    mfontset_modify_entry (fontset_no_ctl, msymbol ("devanagari"), Mnil, Mnil,
                           dev_font, no_ctl, 0);
-    mfontset_modify_entry (fontset, msymbol ("thai"), Mnil, Mnil,
+    mfontset_modify_entry (fontset_no_ctl, msymbol ("thai"), Mnil, Mnil,
                           thai_font, no_ctl, 0);
-    mfontset_modify_entry (fontset, msymbol ("tibetan"), Mnil, Mnil,
+    mfontset_modify_entry (fontset_no_ctl, msymbol ("tibetan"), Mnil, Mnil,
                           tib_font, no_ctl, 0);
     face_no_ctl_fontset = mface ();
-    mface_put_prop (face_no_ctl_fontset, Mfontset, fontset);
-    m17n_object_unref (fontset);
+    mface_put_prop (face_no_ctl_fontset, Mfontset, fontset_no_ctl);
+    m17n_object_unref (fontset_no_ctl);
 
     free (dev_font);
     free (thai_font);
     free (tib_font);
   }
 
-  setup_input_methods (with_xim);
+  setup_input_methods (with_xim, initial_input_method);
 
   gc = DefaultGC (display, screen);
 
@@ -2505,12 +2978,12 @@ main (int argc, char **argv)
     SetMenu (menus[1], 0, "auto", NULL, InputMethodProc, -1, 0);
     for (i = 0; i < num_input_methods; i++)
       {
-       MInputMethod *im = input_method_table[i];
+       InputMethodInfo *im = input_method_table + i;
        char *name1, *name2;
 
        if (im->language != Mnil && im->language != Mt)
          {
-           MSymbol sym = msymbol_get (im->language, Mlanguage);
+           MSymbol sym = mlanguage_name (im->language);
            if (sym == Mnil)
              name1 = msymbol_name (im->language);
            else
@@ -2540,6 +3013,14 @@ main (int argc, char **argv)
     for (i = 0; i < num_input_methods + 2; i++)
       InputMethodMenus[i] = menus[i].w;
 
+    if (filter)
+      {
+       SetMenu (menus[0], 0, filter, NULL, FilterProc, filter, 0);
+       w = create_menu_button (ShellWidget, HeadWidget, w, "Filter",
+                               "Filter Menu", menus, 1,
+                               "Select filter to run");
+      }
+
     input_status_width = font_width * 8;
     input_status_height = (font_ascent + font_descent) * 2.4;
     input_status_pixmap = XCreatePixmap (display, RootWindow (display, screen),
@@ -2554,7 +3035,7 @@ main (int argc, char **argv)
        = prop.color_left = prop.color_right = Mnil;
       prop.inner_hmargin = prop.inner_vmargin = 1;
       prop.outer_hmargin = prop.outer_vmargin = 0;
-      face_input_status = mface ();
+      face_input_status = mface_copy (face_default);
       mface_put_prop (face_input_status, Mbox, &prop);
     }
 
@@ -2629,14 +3110,14 @@ main (int argc, char **argv)
            MSymbol fullname;
 
            if (sym != Mnil
-               && ((fullname = msymbol_get (sym, Mlanguage)) != Mnil))
+               && ((fullname = mlanguage_name (sym)) != Mnil))
              {
                char *name = msymbol_name (fullname);
                char c = name[0];
 
-               if (c >= 'A' && c <= 'Z')
+               if (c >= 'a' && c <= 'z')
                  {
-                   int idx = (c < 'U') ? (c - 'A') / 2 : 10;
+                   int idx = (c < 'u') ? (c - 'a') / 2 : 10;
 
                    pl = plist[idx];
                    if (! pl)
@@ -2719,9 +3200,7 @@ main (int argc, char **argv)
   memset (&control, 0, sizeof control);
   control.two_dimensional = 1;
   control.enable_bidi = 1;
-#if 0
   control.anti_alias = 1;
-#endif
   control.min_line_ascent = font_ascent;
   control.min_line_descent = font_descent;
   control.max_line_width = win_width;
@@ -2743,7 +3222,8 @@ main (int argc, char **argv)
   if (current_input_context)
     minput_destroy_ic (current_input_context);
   for (i = 0; i < num_input_methods; i++)
-    minput_close_im (input_method_table[i]);
+    if (input_method_table[i].im)
+      minput_close_im (input_method_table[i].im);
   m17n_object_unref (frame);
   m17n_object_unref (mt);
   m17n_object_unref (face_xxx_large);
@@ -2753,18 +3233,16 @@ main (int argc, char **argv)
   m17n_object_unref (face_times);
   m17n_object_unref (face_dv_ttyogesh);
   m17n_object_unref (face_freesans);
+  m17n_object_unref (face_freeserif);
   m17n_object_unref (face_freemono);
   m17n_object_unref (face_default_fontset);
   m17n_object_unref (face_no_ctl_fontset);
   m17n_object_unref (face_input_status);
+  m17n_object_unref (face_default);
+  m17n_object_unref (default_face_list);
   m17n_object_unref (selection);
-
-  M17N_FINI ();
-
-  free (fontset_name);
-  free (filename);
-  free (input_method_table);
-  free (InputMethodMenus);
+  if (font)
+    free (font);
 
   XFreeGC (display, mono_gc);
   XFreeGC (display, mono_gc_inv);
@@ -2774,6 +3252,27 @@ main (int argc, char **argv)
   XtDestroyWidget (ShellWidget);
   XtDestroyApplicationContext (context);
 
+  M17N_FINI ();
+
+  free (font_name);
+  free (fontset_name);
+  free (filename);
+  free (input_method_table);
+  free (InputMethodMenus);
+
   exit (0);
 }
+
+#else  /* not HAVE_X11_XAW_COMMAND_H */
+
+int
+main (int argc, char **argv)
+{
+  fprintf (stderr,
+          "Building of this program failed (lack of some header files)\n");
+  exit (1);
+}
+
+#endif /* not HAVE_X11_XAW_COMMAND_H */
+
 #endif /* not FOR_DOXYGEN */