(covert_selection): Handle explicit request of
[m17n/m17n-lib.git] / example / medit.c
index eb30560..5680253 100644 (file)
@@ -1,4 +1,4 @@
-/* medit.c -- simple multilingual editor.
+/* medit.c -- simple multilingual editor.              -*- coding: euc-jp; -*-
    Copyright (C) 2003, 2004
      National Institute of Advanced Industrial Science and Technology (AIST)
      Registration Number H15PRO112
@@ -21,7 +21,7 @@
    02111-1307, USA.  */
 
 /***en
-    @page medit edit multilingual text
+    @enpage medit edit multilingual text
 
     @section medit-synopsis SYNOPSIS
 
     toolkit libraries or to implement XOM (X Outout Method), not for
     direct use from application programs.
 */
+/***ja
+    @japage medit Â¿¸À¸ì¥Æ¥­¥¹¥È¤ÎÊÔ½¸
+
+    @section medit-synopsis SYNOPSIS
+
+    medit [ XT-OPTION ...] [ OPTION ... ] FILE
+
+    @section medit-description DESCRIPTION
+
+    FILE ¤ò¥¦¥£¥ó¥É¥¦¤Ëɽ¼¨¤·¡¢¥æ¡¼¥¶¤¬ÊÔ½¸¤Ç¤­¤ë¤è¤¦¤Ë¤¹¤ë¡£
+
+    XT-OPTIONs ¤Ï Xt ¤Îɸ½à¤Î°ú¿ô¤Ç¤¢¤ë¡£ (e.g. -fn, -fg). 
+
+    °Ê²¼¤Î¥ª¥×¥·¥ç¥ó¤¬ÍøÍѤǤ­¤ë¡£ 
+
+    <ul>
+
+    <li> --version
+
+    ¥Ð¡¼¥¸¥ç¥óÈÖ¹æ¤òɽ¼¨¤¹¤ë¡£ 
+
+    <li> -h, --help
+
+    ¤³¤Î¥á¥Ã¥»¡¼¥¸¤òɽ¼¨¤¹¤ë¡£ 
+
+    </ul>
+
+    ¤³¤Î¥×¥í¥°¥é¥à¤Ï m17n GUI API ¤Î»È¤¤Êý¤ò¼¨¤¹¤â¤Î¤Ç¤¢¤ë¡£medit ¤Ïľ 
+    ÀÜ GUI API ¤ò»È¤Ã¤Æ¤¤¤ë¤¬¡¢¤³¤Î API ¤Ï¼ç¤Ë¥Ä¡¼¥ë¥­¥Ã¥È¥é¥¤¥Ö¥é¥ê¤ä
+    XOM (X Outout Method) ¤Î¼ÂÁõÍѤǤ¢¤ê¡¢¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¥×¥í¥°¥é ¥à
+    ¤«¤é¤ÎľÀܤÎÍøÍѤò°Õ¿Þ¤·¤Æ¤¤¤Ê¤¤¡£
+*/
 
 #ifndef FOR_DOXYGEN
 
 #include <m17n-misc.h>
 #include <m17n-X.h>
 
-#define VERSION "1.0"
+#define VERSION "1.1"
 
 /* Global variables.  */
 
@@ -137,20 +169,29 @@ Pixmap CheckPixmap;
 MFrame *frame;
 MText *mt;
 int nchars;                    /* == mtext_len (mt) */
-MDrawControl control;
+MDrawControl control, input_status_control;
 MTextProperty *selection;
 
 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 auto_input_method = 0;
@@ -177,6 +218,7 @@ struct FaceRec
     {"times", &face_times},
     {"dv-ttyogesh", &face_dv_ttyogesh},
     {"freesans", &face_freesans},
+    {"freeserif", &face_freeserif},
     {"freemono", &face_freemono},
 
     {"Menu Style", NULL},
@@ -325,11 +367,11 @@ 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.  The lihe is a cursor line if the
-     cursor is at the position above Y0, otherwise the top line.  */
+  /* Find a line closest to y0.  It is a cursor line if the cursor is
+     Y0, otherwise the top line.  */
   if (y0 >= cur.y0)
     line = &cur;
   else
@@ -383,16 +425,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)
@@ -416,12 +461,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; 
@@ -435,8 +480,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.this.height);
        }
       DRAW_TEXT (cursor.x, cur.y0 + cur.ascent, cursor.from, cursor.to);
     }
@@ -498,28 +543,28 @@ update_selection ()
 
   if (from < top.from)
     {
-      GLYPH_INFO (bol (from, 0), from, info);
-      sel_start.ascent = -info.this.y;
-      sel_start.from = info.line_from;
-      sel_start.to = info.line_to;
-      TEXT_EXTENTS (from, top.from, rect);      
-      sel_start.y0 = - rect.height;
-      sel_start.y1 = sel_start.y0 + info.this.height;
+      int pos = bol (from, 0);
+
+      TEXT_EXTENTS (pos, top.from, rect);
+      sel_start.y0 = top.y0 - rect.height;
+      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;
     }
   else
     {
       GLYPH_INFO (top.from, from, info);
       sel_start.y0 = top.ascent + info.y + info.this.y;
-      sel_start.y1 = sel_start.y0 + info.this.height;
-      sel_start.ascent = -info.this.y;
-      sel_start.from = info.line_from;
-      sel_start.to = info.line_to;
     }
+  sel_start.ascent = -info.this.y;
+  sel_start.y1 = sel_start.y0 + info.this.height;
+  sel_start.from = info.line_from;
+  sel_start.to = info.line_to;
 
   if (to <= sel_start.to)
     {
       sel_end = sel_start;
-      to = bol (to - 1, 1) - 1;
       if (to >= sel_end.to)
        {
          GLYPH_INFO (sel_start.from, to, info);
@@ -529,7 +574,6 @@ update_selection ()
     }
   else
     {
-      to = bol (to - 1, 1) - 1;
       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;
@@ -627,7 +671,7 @@ select_input_method (idx)
     }
   if (idx >= 0)
     {
-      MInputMethod *im = input_method_table[idx];
+      InputMethodInfo *im = input_method_table + idx;
 
       if (im->language == Mnil)
        {
@@ -637,7 +681,7 @@ select_input_method (idx)
          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);
+         current_input_context = minput_create_ic (im->im, &arg_xic);
        }
       else
        {
@@ -646,7 +690,7 @@ select_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, &arg_ic);
+         current_input_context = minput_create_ic (im->im, &arg_ic);
        }
 
       if (current_input_context)
@@ -677,6 +721,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);
@@ -697,57 +744,60 @@ 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)
     {
@@ -782,10 +832,24 @@ 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)
                  break;
-             if (i < num_input_methods)
-               select_input_method (i);
+             if (i < num_input_methods
+                 && input_method_table[i].available >= 0)
+               {
+                 if (! input_method_table[i].im)
+                   {
+                     input_method_table[i].im = 
+                       minput_open_im (input_method_table[i].language,
+                                       input_method_table[i].name, NULL);
+                     if (! input_method_table[i].im)
+                       input_method_table[i].available = -1;
+                   }
+                 if (input_method_table[i].im)
+                   select_input_method (i);
+                 else
+                   select_input_method (-1);
+               }
              else
                select_input_method (-1);
            }
@@ -879,7 +943,7 @@ 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);
@@ -926,8 +990,9 @@ insert_chars (MText *newtext)
 }
 
 
-/* Convert the currently selected text to COMPOUND-TEXT.  It is called
-   when someone requests the current value of the selection.  */
+/* 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,
@@ -937,14 +1002,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;
 }
 
@@ -973,12 +1076,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 ();
@@ -1022,6 +1133,18 @@ ExposeProc (Widget w, XEvent *event, String *str, Cardinal *num)
       update_top (0);
       update_cursor (0, 1);
       redraw (0, win_height, 0, 1);
+      {
+       int idx = current_input_method;
+
+       current_input_method = -1;
+       input_method_table[idx].im = 
+         minput_open_im (input_method_table[idx].language,
+                           input_method_table[idx].name, NULL);
+       if (input_method_table[idx].im)
+         select_input_method (idx);
+       else
+         input_method_table[idx].available = -1;
+      }
       show_cursor (NULL);
     }
   else
@@ -1143,25 +1266,61 @@ ButtonMoveProc (Widget w, XEvent *event, String *str, Cardinal *num)
 
       if (cursor.from == from)
        {
-         /* Start position of selection changed.  */
-         select_region (pos, to);
-         if (pos > from)
-           /* Shrunken.  Previous selection face must be cleared.  */
-           redraw (start_y0, sel_start.y1, 1, 0);
+         /* Starting position changed.  */
+         if (pos <= from)
+           {
+             /* Enlarged.  We can simply overdraw.  */
+             select_region (pos, to);
+             redraw (sel_start.y0, start_y1, 0, 0);
+           }
+         else if (pos < to)
+           {
+             /* Shrunken.  Previous selection face must be cleared.  */
+             select_region (pos, to);
+             redraw (start_y0, sel_start.y1, 1, 0);
+           }
+         else if (pos == to)
+           {
+             /* Shrunken to zero.  */
+             XtDisownSelection (w, XA_PRIMARY, CurrentTime);
+             mtext_detach_property (selection);
+             redraw (start_y0, end_y1, 1, 0);
+           }
          else
-           /* Enlarged.  We can simply overdraw.  */
-           redraw (sel_start.y0, start_y1, 0, 0);
+           {
+             /* Full update is necessary.  */
+             select_region (to, pos);
+             redraw (start_y0, sel_end.y1, 1, 0);
+           }
        }
       else
        {
-         /* End position of selection changed.  */
-         select_region (from, pos);
-         if (pos < to)
-           /* Shrunken.  Previous selection face must be cleared.  */
-           redraw (sel_end.y0, end_y1, 1, 0);
+         /* Ending position changed.  */
+         if (pos < from)
+           {
+             /* Full update is necessary.  */
+             select_region (pos, from);
+             redraw (sel_start.y0, end_y1, 1, 0);
+           }
+         else if (pos == from)
+           {
+             /* Shrunken to zero.  */
+             XtDisownSelection (w, XA_PRIMARY, CurrentTime);
+             mtext_detach_property (selection);
+             redraw (start_y0, end_y1, 1, 0);
+           }
+         else if (pos < to)
+           {
+             /* Shrunken.  Previous selection face must be cleared.  */
+             select_region (from, pos);
+             redraw (sel_end.y0, end_y1, 1, 0);
+           }
          else
-           /* Enlarged.  We can simply overdraw.  */
-           redraw (end_y0, sel_end.y1, 0, 0);
+           {
+             /* Enlarged.  We can simply overdraw.  */
+             select_region (from, pos);
+             redraw (end_y0, sel_end.y1, 0, 0);
+           }
        }
     }
   else
@@ -1633,6 +1792,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);
 }
 
@@ -1662,12 +1822,25 @@ InputMethodProc (Widget w, XtPointer client_data, XtPointer call_data)
       auto_input_method = 1;
       hide_cursor ();
     }
-  else
-    select_input_method (idx);
+  else if (input_method_table[idx].available >= 0)
+    {
+      if (! input_method_table[idx].im)
+       {
+         input_method_table[idx].im = 
+           minput_open_im (input_method_table[idx].language,
+                           input_method_table[idx].name, NULL);
+         if (! input_method_table[idx].im)
+           input_method_table[idx].available = -1;
+       }
+      if (input_method_table[idx].im)
+       select_input_method (idx);
+    }
   XtSetArg (arg[0], XtNleftBitmap, CheckPixmap);
   XtSetValues (InputMethodMenus[idx + 2], arg, 1);
 }
 
+MPlist *default_face_list;
+
 void
 FaceProc (Widget w, XtPointer client_data, XtPointer call_data)
 {
@@ -1676,7 +1849,35 @@ FaceProc (Widget w, XtPointer client_data, XtPointer call_data)
   int old_y1;
 
   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);
@@ -1792,10 +1993,11 @@ input_status (MInputContext *ic, MSymbol command)
        mtext_put_prop (ic->status, 0, mtext_len (ic->status),
                        Mlanguage, ic->im->language);
       mdraw_text_extents (frame, ic->status, 0, mtext_len (ic->status),
-                         NULL, NULL, NULL, &rect);
-      mdraw_text (frame, (MDrawWindow) input_status_pixmap,
-                 input_status_width - rect.width - 2, - rect.y,
-                 ic->status, 0, mtext_len (ic->status));
+                         &input_status_control, NULL, NULL, &rect);
+      mdraw_text_with_control (frame, (MDrawWindow) input_status_pixmap,
+                              input_status_width - rect.width - 2, - rect.y,
+                              ic->status, 0, mtext_len (ic->status),
+                              &input_status_control);
     }
   XtSetArg (arg[0], XtNbitmap, input_status_pixmap);
   XtSetValues (CurIMStatus, arg, 1);
@@ -1804,8 +2006,8 @@ input_status (MInputContext *ic, MSymbol command)
 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)
@@ -1822,18 +2024,29 @@ compare_input_method (const void *elt1, const void *elt2)
 }
 
 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;
+  char *lang_name = NULL, *method_name = NULL;
+
+  if (initial_input_method)
+    {
+      char *p = strchr (initial_input_method, '-');
+      if (p)
+       lang_name = initial_input_method, method_name = p + 1, *p = '\0';
+      else
+       method_name = initial_input_method;
+    }
 
   num_input_methods = mplist_length (plist);
 
   if (with_xim)
     {
+      MInputXIMArgIM arg_xim;
+
       arg_xim.display = display;
       arg_xim.db = NULL;  
       arg_xim.res_name = arg_xim.res_class = NULL;
@@ -1843,9 +2056,16 @@ setup_input_methods (int with_xim)
       if (im)
        num_input_methods++;
     }
-  input_method_table = calloc (num_input_methods, sizeof (MInputMethod *));
+  input_method_table = calloc (num_input_methods, sizeof (InputMethodInfo));
   if (im)
-    input_method_table[i++] = im;
+    {
+      input_method_table[i].available = 1;
+      input_method_table[i].language = Mnil;
+      input_method_table[i].name = im->name;
+      input_method_table[i].im = im;
+      i++;
+    }
+
   for (pl = plist; mplist_key (pl) != Mnil; pl = mplist_next (pl))
     {
       MDatabase *mdb = mplist_value (pl);
@@ -1853,9 +2073,9 @@ setup_input_methods (int with_xim)
 
       if (tag[1] != Mnil)
        {
-         im = minput_open_im (tag[1], tag[2], NULL);
-         if (im)
-           input_method_table[i++] = im;
+         input_method_table[i].language = tag[1];
+         input_method_table[i].name = tag[2];
+         i++;
        }
     }
 
@@ -1871,6 +2091,17 @@ setup_input_methods (int with_xim)
              (void *) input_status);
   mplist_put (minput_driver->callback_list, Minput_status_done,
              (void *) input_status);
+
+  if (method_name)
+    for (i = 0; i < num_input_methods; i++)
+      if (strcmp (method_name, msymbol_name (input_method_table[i].name)) == 0
+         && (lang_name
+             ? strcmp (lang_name, msymbol_name (input_method_table[i].language)) == 0
+             : input_method_table[i].language == Mt))
+       {
+         current_input_method = i;
+         break;
+       }
 }
 
 
@@ -2131,8 +2362,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);
 }
 
@@ -2141,6 +2378,8 @@ main (int argc, char **argv)
 {
   Widget form, BodyWidget, w;
   char *fontset_name = NULL;
+  int fontsize = 120;
+  char *initial_input_method = NULL;
   int col = 80, row = 32;
   /* Translation table for TextWidget.  */
   String trans = "<Expose>: Expose()\n\
@@ -2194,11 +2433,23 @@ 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], "--im"))
+       {
+         i++;
+         initial_input_method = strdup (argv[i]);
+       }
       else if (! strcmp (argv[i], "--with-xim"))
        {
          with_xim = 1;
@@ -2209,7 +2460,7 @@ main (int argc, char **argv)
        }
       else
        {
-         fprintf (stderr, "Unknown option: %s", argv[i]);
+         fprintf (stderr, "Unknown option: %s\n", argv[i]);
          help_exit (argv[0], 1);
        }
     }
@@ -2230,8 +2481,9 @@ main (int argc, char **argv)
   {
     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);
   }
@@ -2242,25 +2494,34 @@ 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 || fontsize != 120)
       {
        MFontset *fontset = mfontset (fontset_name);
        
        face = mface ();
        mface_put_prop (face, Mfontset, fontset);
+       mface_put_prop (face, Msize, (void *) fontsize);
        m17n_object_unref (fontset);
        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));
@@ -2298,6 +2559,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"));
 
@@ -2337,7 +2600,7 @@ main (int argc, char **argv)
     free (tib_font);
   }
 
-  setup_input_methods (with_xim);
+  setup_input_methods (with_xim, initial_input_method);
 
   gc = DefaultGC (display, screen);
 
@@ -2437,7 +2700,7 @@ 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)
@@ -2486,7 +2749,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);
     }
 
@@ -2584,7 +2847,7 @@ main (int argc, char **argv)
       for (i = 0; i < 11; i++)
        if (plist[i])
          {
-           char *name = malloc (9);
+           char *name = alloca (9);
 
            sprintf (name, "Menu %c-%c", 'A' + i * 2, 'A' + i * 2 + 1);
            if (i == 10)
@@ -2651,6 +2914,7 @@ main (int argc, char **argv)
   memset (&control, 0, sizeof control);
   control.two_dimensional = 1;
   control.enable_bidi = 1;
+  control.anti_alias = 1;
   control.min_line_ascent = font_ascent;
   control.min_line_descent = font_descent;
   control.max_line_width = win_width;
@@ -2659,6 +2923,9 @@ main (int argc, char **argv)
   control.partial_update = 1;
   control.ignore_formatting_char = 1;
 
+  memset (&input_status_control, 0, sizeof input_status_control);
+  input_status_control.enable_bidi = 1;
+
   XtAppAddActions (context, actions, XtNumber (actions));
   XtRealizeWidget (ShellWidget);
 
@@ -2669,9 +2936,9 @@ 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);
   m17n_object_unref (face_box);
@@ -2680,21 +2947,30 @@ 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);
-
+  XFreeGC (display, mono_gc);
+  XFreeGC (display, mono_gc_inv);
+  XFreeGC (display, gc_inv);
   XtUninstallTranslations (form);
   XtUninstallTranslations (TextWidget);
   XtDestroyWidget (ShellWidget);
   XtDestroyApplicationContext (context);
 
+  M17N_FINI ();
+
+  free (fontset_name);
+  free (filename);
+  free (input_method_table);
+  free (InputMethodMenus);
+
   exit (0);
 }
 #endif /* not FOR_DOXYGEN */