(moduledir): Use ${libdir} instead of ${exec_prefix}/lib.
[m17n/m17n-lib.git] / example / medit.c
index cf7aa7c..fe6fad2 100644 (file)
@@ -1,5 +1,5 @@
 /* medit.c -- simple multilingual editor.              -*- coding: euc-jp; -*-
-   Copyright (C) 2003, 2004
+   Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008
      National Institute of Advanced Industrial Science and Technology (AIST)
      Registration Number H15PRO112
 
@@ -17,7 +17,7 @@
 
    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
@@ -49,7 +49,7 @@
 
     This program is to demonstrate how to use the m17n GUI API.
     Although m17n-edit directly uses the GUI API, the API is mainly
-    for toolkit libraries or to implement XOM (X Outout Method), not
+    for toolkit libraries or to implement XOM (X Output Method), not
     for direct use from application programs.
 */
 /***ja
@@ -81,7 +81,7 @@
 
     ¤³¤Î¥×¥í¥°¥é¥à¤Ï m17n GUI API ¤Î»È¤¤Êý¤ò¼¨¤¹¤â¤Î¤Ç¤¢¤ë¡£m17n-edit
     ¤ÏľÀÜ GUI API ¤ò»È¤Ã¤Æ¤¤¤ë¤¬¡¢¤³¤Î API ¤Ï¼ç¤Ë¥Ä¡¼¥ë¥­¥Ã¥È¥é¥¤¥Ö¥é
-    ¥ê¤äXOM (X Outout Method) ¤Î¼ÂÁõÍѤǤ¢¤ê¡¢¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¥×¥í¥°¥é
+    ¥ê¤äXOM (X Output Method) ¤Î¼ÂÁõÍѤǤ¢¤ê¡¢¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¥×¥í¥°¥é
     ¥à¤«¤é¤ÎľÀܤÎÍøÍѤò°Õ¿Þ¤·¤Æ¤¤¤Ê¤¤¡£
 */
 
 #include <X11/Xaw/SmeLine.h>
 #include <X11/Xaw/MenuButton.h>
 
-#define VERSION "1.2.0"
-
 /* Global variables.  */
 
 char *filename;
@@ -173,6 +171,7 @@ Pixmap CheckPixmap;
 MFrame *frame;
 MText *mt;
 int nchars;                    /* == mtext_len (mt) */
+int mt_modified;
 MDrawControl control, input_status_control;
 MTextProperty *selection;
 
@@ -200,7 +199,9 @@ 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
@@ -257,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.  */
 };
 
@@ -352,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);
 }
 
 
@@ -508,6 +505,7 @@ update_cursor (int pos, int full)
 {
   MDrawMetric rect;
 
+  control.cursor_pos = pos;
   if (full)
     {
       /* CUR is inaccurate.  We can trust only TOP.  */
@@ -666,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)
     {
       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->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->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);
 }
 
@@ -816,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);
@@ -831,24 +877,11 @@ 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
-                 && 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);
-               }
+             if (i < num_input_methods)
+               select_input_method (i);
              else
                select_input_method (-1);
            }
@@ -915,6 +948,8 @@ delete_char (int n)
     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.  */
@@ -928,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;
        }
     }
 
@@ -1196,18 +1224,12 @@ ExposeProc (Widget w, XEvent *event, String *str, Cardinal *num)
       update_cursor (0, 1);
       redraw (0, win_height, 0, 1);
       if (current_input_method >= 0)
-      {
-       int idx = current_input_method;
+       {
+         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)
+         current_input_method = -1;
          select_input_method (idx);
-       else
-         input_method_table[idx].available = -1;
-      }
+       }
       show_cursor (NULL);
     }
   else
@@ -1252,11 +1274,11 @@ ButtonProc (Widget w, XEvent *event, String *str, Cardinal *num)
       redraw (sel_start.y0, sel_end.y1, 1, 0);
     }
   hide_cursor ();
-  if (current_input_context)
+  if (current_input_context
+      && minput_filter (current_input_context, Minput_focus_move, NULL) == 0)
     {
       MText *produced = mtext ();
 
-      minput_reset_ic (current_input_context);
       minput_lookup (current_input_context, Mnil, NULL, produced);
       if (mtext_len (produced) > 0)
        {
@@ -1410,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;
@@ -1490,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)
@@ -1501,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)
@@ -1518,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:
@@ -1686,6 +1762,14 @@ 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 ();
@@ -1857,7 +1941,7 @@ FilterProc (Widget w, XtPointer client_data, XtPointer call_data)
   handle = dlopen (filter_module, RTLD_NOW);
   if (! handle)
     return;
-  *(void **) (&func) = dlsym (handle, "filter");
+  func = (void (*) (MText *, int, int)) dlsym (handle, "filter");
   if (func)
     (*func) (mt, mtext_property_start (selection),
             mtext_property_end (selection));
@@ -1912,42 +1996,33 @@ 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 if (input_method_table[idx].available >= 0)
+  else
     {
-      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);
+      select_input_method (idx);
     }
-  XtSetArg (arg[0], XtNleftBitmap, CheckPixmap);
-  XtSetValues (InputMethodMenus[idx + 2], arg, 1);
 }
 
 MPlist *default_face_list;
@@ -2115,6 +2190,59 @@ 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)
 {
@@ -2130,93 +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, char *initial_input_method)
 {
-  MInputMethod *im = NULL;
   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;
-    }
+  int i;
+  MSymbol Municode = msymbol ("unicode");
 
   num_input_methods = plist ? mplist_length (plist) : 0;
-
   if (with_xim)
-    {
-      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 = minput_open_im (Mnil, msymbol ("xim"), &arg_xim);
-      if (im)
-       num_input_methods++;
-    }
+    num_input_methods++;
   input_method_table = calloc (num_input_methods, sizeof (InputMethodInfo));
-  if (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++;
-    }
 
+  i = 0;
   if (plist)
     {
-      for (pl = plist; mplist_key (pl) != Mnil; pl = mplist_next (pl))
+      for (pl = plist; mplist_key (pl) != Mnil; pl = mplist_next (pl), i++)
        {
          MDatabase *mdb = mplist_value (pl);
          MSymbol *tag = mdatabase_tag (mdb);
 
-         if (tag[1] != Mnil)
+         if (tag[2] == Mnil)
+           i--, num_input_methods--;
+         else
            {
              input_method_table[i].language = tag[1];
              input_method_table[i].name = tag[2];
-             i++;
            }
        }
-
       m17n_object_unref (plist);
     }
-  num_input_methods = i;
+  if (with_xim)
+    {
+      input_method_table[i].language = Mnil;
+      input_method_table[i].name = msymbol ("xim");
+      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;
 
-  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);
+  if (initial_input_method)
+    {
+      char *lang_name, *method_name;
+      char *p = strchr (initial_input_method, '-');
 
-  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;
-       }
+      if (p && p[1])
+       lang_name = initial_input_method, *p = '\0', method_name = p + 1;
+      else
+       lang_name = "t", method_name = initial_input_method;
+
+      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;
+         }
+    }
 }
 
 
@@ -2399,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,
@@ -2457,7 +2584,9 @@ XtActionsRec actions[] = {
   {"ButtonRelease", ButtonReleaseProc},
   {"ButtonMotion", ButtonMoveProc},
   {"Button2Press", Button2Proc},
-  {"MenuHelp", MenuHelpProc}
+  {"MenuHelp", MenuHelpProc},
+  {"FocusIn", FocusInProc},
+  {"FocusOut", FocusOutProc}
 };
 
 
@@ -2493,6 +2622,7 @@ 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;
@@ -2507,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\
@@ -2522,6 +2654,7 @@ main (int argc, char **argv)
   int with_xim = 0;
   int i, j;
   char *filter = NULL;
+  MFont *font = NULL;
 
   setlocale (LC_ALL, "");
   /* Create the top shell.  */
@@ -2539,8 +2672,8 @@ main (int argc, char **argv)
        help_exit (argv[0], 0);
       else if (! strcmp (argv[i], "--version"))
        {
-         printf ("m17n-edit (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"))
@@ -2561,6 +2694,11 @@ main (int argc, char **argv)
          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++;
@@ -2624,18 +2762,32 @@ main (int argc, char **argv)
 
   {
     MPlist *plist = mplist ();
-    MFace *face;
     MFont *font;
 
     mplist_put (plist, msymbol ("widget"), ShellWidget);
-    if (fontset_name || fontsize > 0)
+    if (fontset_name || font_name || fontsize > 0)
       {
-       MFontset *fontset = mfontset (fontset_name);
-       
-       face = mface ();
-       mface_put_prop (face, Mfontset, fontset);
-       mface_put_prop (face, Msize, (void *) fontsize);
-       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);
       }
@@ -2695,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");
 
@@ -2706,18 +2858,20 @@ 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);
@@ -2829,7 +2983,7 @@ main (int argc, char **argv)
 
        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
@@ -2956,7 +3110,7 @@ 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];
@@ -3087,6 +3241,8 @@ main (int argc, char **argv)
   m17n_object_unref (face_default);
   m17n_object_unref (default_face_list);
   m17n_object_unref (selection);
+  if (font)
+    free (font);
 
   XFreeGC (display, mono_gc);
   XFreeGC (display, mono_gc_inv);
@@ -3098,6 +3254,7 @@ main (int argc, char **argv)
 
   M17N_FINI ();
 
+  free (font_name);
   free (fontset_name);
   free (filename);
   free (input_method_table);