(AM_CPPFLAGS): Set it to @CONFIG_FLAGS@.
[m17n/m17n-lib.git] / example / medit.c
index 37ced11..63701ca 100644 (file)
    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 Outout 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 Outout Method) ¤Î¼ÂÁõÍѤǤ¢¤ê¡¢¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¥×¥í¥°¥é
+    ¥à¤«¤é¤ÎľÀܤÎÍøÍѤò°Õ¿Þ¤·¤Æ¤¤¤Ê¤¤¡£
 */
 
 #ifndef FOR_DOXYGEN
 #include <unistd.h>
 #include <libgen.h>
 #include <locale.h>
+#include <dlfcn.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 <config.h>
+
+#ifdef HAVE_X11_XAW_COMMAND_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.1"
+#define VERSION "1.2.0"
 
 /* Global variables.  */
 
@@ -172,6 +178,8 @@ int nchars;                 /* == mtext_len (mt) */
 MDrawControl control, input_status_control;
 MTextProperty *selection;
 
+MSymbol Mword;
+
 MFace *face_default;
 MFace *face_xxx_large;
 MFace *face_box;
@@ -490,7 +498,7 @@ 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)
@@ -795,14 +803,8 @@ show_cursor (XtPointer client_data)
 
   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);
@@ -902,8 +904,9 @@ 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;
@@ -942,6 +945,10 @@ delete_char (int n)
     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;
 
@@ -956,6 +963,7 @@ insert_chars (MText *newtext)
   int n = mtext_len (newtext);
   MDrawMetric rect;
   int y0, old_y1, new_y1;
+  int line_from;
 
   if (SELECTEDP ())
     {
@@ -966,9 +974,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;
@@ -984,6 +998,57 @@ insert_chars (MText *newtext)
 }
 
 
+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.  */
@@ -1184,6 +1249,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)
+    {
+      MText *produced = mtext ();
+
+      minput_reset_ic (current_input_context);
+      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);
 }
 
@@ -1575,6 +1654,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)
        {
@@ -1721,8 +1816,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)
 {
@@ -1734,7 +1827,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++)
     {
@@ -1750,6 +1843,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;
+  *(void **) (&func) = 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;
@@ -2038,7 +2150,7 @@ setup_input_methods (int with_xim, char *initial_input_method)
        method_name = initial_input_method;
     }
 
-  num_input_methods = mplist_length (plist);
+  num_input_methods = plist ? mplist_length (plist) : 0;
 
   if (with_xim)
     {
@@ -2063,20 +2175,23 @@ setup_input_methods (int with_xim, char *initial_input_method)
       i++;
     }
 
-  for (pl = plist; mplist_key (pl) != Mnil; pl = mplist_next (pl))
+  if (plist)
     {
-      MDatabase *mdb = mplist_value (pl);
-      MSymbol *tag = mdatabase_tag (mdb);
-
-      if (tag[1] != Mnil)
+      for (pl = plist; mplist_key (pl) != Mnil; pl = mplist_next (pl))
        {
-         input_method_table[i].language = tag[1];
-         input_method_table[i].name = tag[2];
-         i++;
+         MDatabase *mdb = mplist_value (pl);
+         MSymbol *tag = mdatabase_tag (mdb);
+
+         if (tag[1] != Mnil)
+           {
+             input_method_table[i].language = tag[1];
+             input_method_table[i].name = tag[2];
+             i++;
+           }
        }
-    }
 
-  m17n_object_unref (plist);
+      m17n_object_unref (plist);
+    }
   num_input_methods = i;
   qsort (input_method_table, num_input_methods, sizeof input_method_table[0],
         compare_input_method);
@@ -2403,11 +2518,12 @@ main (int argc, char **argv)
   int font_width, font_ascent, font_descent;
   int with_xim = 0;
   int i, j;
+  char *filter = 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));
@@ -2420,7 +2536,7 @@ main (int argc, char **argv)
        help_exit (argv[0], 0);
       else if (! strcmp (argv[i], "--version"))
        {
-         printf ("medit (m17n library) %s\n", VERSION);
+         printf ("m17n-edit (m17n library) %s\n", VERSION);
          printf ("Copyright (C) 2003 AIST, JAPAN\n");
          exit (0);
        }
@@ -2451,6 +2567,11 @@ main (int argc, char **argv)
        {
          with_xim = 1;
        }
+      else if (! strcmp (argv[i], "--filter"))
+       {
+         i++;
+         filter = argv[i];
+       }
       else if (argv[i][0] != '-')
        {
          filename = strdup (argv[i]);
@@ -2462,19 +2583,22 @@ main (int argc, char **argv)
        }
     }
   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 ();
 
@@ -2732,6 +2856,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),
@@ -2826,9 +2958,9 @@ main (int argc, char **argv)
                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)
@@ -2970,4 +3102,17 @@ main (int argc, char **argv)
 
   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 */