diff lib/Ruby.c @ 16:598fcbe482b5

imported patch 19_kinput2-v3.1-ruby.patch
author Yoshiki Yazawa <yaz@honeyplanet.jp>
date Mon, 08 Mar 2010 20:38:17 +0900
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/Ruby.c	Mon Mar 08 20:38:17 2010 +0900
@@ -0,0 +1,947 @@
+/*
+ * Copyright (c) 1990  Software Research Associates, Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Software Research Associates not be
+ * used in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.  Software Research
+ * Associates makes no representations about the suitability of this software
+ * for any purpose.  It is provided "as is" without express or implied
+ * warranty.
+ *
+ * Author:  Makoto Ishisone, Software Research Associates, Inc., Japan
+ */
+
+/* Copyright 1991 NEC Corporation, Tokyo, Japan.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted,
+ * provided that the above copyright notice appear in all copies and that
+ * both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of NEC Corporation
+ * not be used in advertising or publicity pertaining to distribution
+ * of the software without specific, written prior permission.  NEC 
+ * Corporation makes no representations about the suitability of this
+ * software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ * NEC CORPORATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN 
+ * NO EVENT SHALL NEC CORPORATION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF 
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR 
+ * OTHER TORTUOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 
+ * PERFORMANCE OF THIS SOFTWARE. 
+ *
+ * Author: Akira Kon, NEC Corporation.  (kon@d1.bs2.mt.nec.co.jp)
+ */
+
+/* Copyright 2003 Hiroyuki Komatsu <komatsu@taiyaki.org> (Ruby.c) */
+
+/* 直さなければならないところ
+
+ ・Destroy が呼ばれないので CloseUIContext できない。
+ ・モード領域の大きさ。(これは他のファイルだろうな)
+
+ */
+
+#ifndef lint
+static char *rcsid = "$Id: Ruby.c,v 1.2 2003/06/10 02:11:23 komatsu Exp $";
+#endif
+
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+#include <X11/Xmu/Atoms.h>
+#define XK_KATAKANA
+#include <X11/keysym.h>
+#if XtSpecificationRelease > 4
+#include <X11/Xfuncs.h>
+#endif
+
+#include "RubyP.h"
+#include "DebugPrint.h"
+
+#define wchar_t wchar
+
+#include "ruby-c.h"
+
+static XtResource resources[] = {
+#define offset(field) XtOffset(RubyObject, ruby.field)
+    { XtNrubyhost, XtCRubyhost, XtRString, sizeof(String),
+	offset(rubyhost), XtRString, NULL },
+    { XtNrubyfile, XtCRubyfile, XtRString, sizeof(String),
+	offset(rubyfile), XtRString, NULL },
+    { XtNsendReturnByString, XtCSendReturnByString,
+	XtRBoolean, sizeof(Boolean),
+	offset(sendReturnByString), XtRBoolean, False },
+#undef offset
+};
+
+static void ClassInitialize();
+static void Initialize(), Destroy();
+static Boolean SetValues();
+static int InputEvent();
+static ICString *GetMode();
+static int CursorPos();
+static int NumSegments();
+static ICString *GetSegment();
+static int CompareSegment();
+static ICString *GetItemList();
+static int SelectItem();
+static int ConvertedString();
+static int ClearConversion();
+static int GetTriggerKeys();
+static int PreeditString();
+static int StatusString();
+
+static void convend();
+
+#if 1 /* KC_SETLISTCALLBACK */
+static void openSelection();
+#define SELECTION_SET 0 /* SelectionStart をしても良いと言う情報を設定する */
+#define SELECTION_DO  1 /* 実際に SelectionStart を開始する */
+#else /* !KC_SETLISTCALLBACK */
+#define openSelection(x, y, z)
+#endif /* !KC_SETLISTCALLBACK */
+
+static ICString *GetAuxSegments();
+
+RubyClassRec rubyClassRec = {
+  { /* object fields */
+    /* superclass		*/	(WidgetClass) &inputConvClassRec,
+    /* class_name		*/	"Ruby",
+    /* widget_size		*/	sizeof(RubyRec),
+    /* class_initialize		*/	ClassInitialize,
+    /* class_part_initialize	*/	NULL,
+    /* class_inited		*/	FALSE,
+    /* initialize		*/	Initialize,
+    /* initialize_hook		*/	NULL,
+    /* obj1			*/	NULL,
+    /* obj2			*/	NULL,
+    /* obj3			*/	0,
+    /* resources		*/	resources,
+    /* num_resources		*/	XtNumber(resources),
+    /* xrm_class		*/	NULLQUARK,
+    /* obj4			*/	FALSE,
+    /* obj5			*/	FALSE,
+    /* obj6			*/	FALSE,
+    /* obj7			*/	FALSE,
+    /* destroy			*/	Destroy,
+    /* obj8			*/	NULL,
+    /* obj9			*/	NULL,
+    /* set_values		*/	SetValues,
+    /* set_values_hook		*/	NULL,
+    /* obj10			*/	NULL,
+    /* get_values_hook		*/	NULL,
+    /* obj11			*/	NULL,
+    /* version			*/	XtVersion,
+    /* callback_private		*/	NULL,
+    /* obj12			*/	NULL,
+    /* obj13			*/	NULL,
+    /* obj14			*/	NULL,
+    /* extension		*/	NULL
+  },
+  { /* inputConv fields */
+    /* InputEvent		*/	InputEvent,
+    /* GetMode			*/	GetMode,
+    /* CursorPos		*/	CursorPos,
+    /* NumSegments		*/	NumSegments,
+    /* GetSegment		*/	GetSegment,
+    /* CompareSegment		*/	CompareSegment,
+    /* GetItemList		*/	GetItemList,
+    /* SelectItem		*/	SelectItem,
+    /* GetConvertedString	*/	ConvertedString,
+    /* ClearConversion		*/	ClearConversion,
+    /* GetAuxSegments		*/	GetAuxSegments,
+    /* SupportMultipleObjects	*/	True,
+    /* GetTriggerKeys		*/	GetTriggerKeys,
+    /* num_trigger_keys		*/	0,
+    /* trigger_keys		*/	NULL,
+    /* GetPreeditString		*/	PreeditString,
+    /* GetStatusString		*/	StatusString,
+    /* NoMoreObjects		*/	False,
+  },
+  { /* ruby fields */
+    /* foo			*/	0,
+  }
+};
+
+WidgetClass rubyObjectClass = (WidgetClass)&rubyClassRec;
+
+static void fix();
+
+static ICString *SymbolList;
+static int NumSymbols;
+
+static void addObject();
+static void deleteObject();
+
+static Display *displaybell = (Display *)0;
+
+static void rubyEUCtoICString();
+static void rubyEUCArraytoICStringArray();
+static void rubySelectionEvent();
+static void rubySelectionDisplay();
+static void rubyDialogDisplay();
+static void rubyDisplayPreEdit();
+
+typedef struct {
+  ICString *array;
+  int length;
+} ICStringArray;
+
+static ICString *ruby_tmp_seg; 
+static ICStringArray *ruby_cand_list;
+
+static void
+ClassInitialize()
+{
+  ruby_init();
+
+  ruby_tmp_seg = XtMalloc(sizeof(ICString));
+  ruby_tmp_seg->nchars = 0;
+  ruby_tmp_seg->nbytes = 0;
+  ruby_cand_list = XtMalloc(sizeof(ICStringArray));
+  ruby_cand_list->length = 0;
+  
+  ruby_eval("$LOAD_PATH.concat(eval(`ruby -e 'p $LOAD_PATH'`))");
+  ruby_eval("$LOAD_PATH.uniq!");
+
+  if (ruby_eval("ENV['KINPUT2_RUBY']") != Qnil) {
+    ruby_eval("require ENV['KINPUT2_RUBY']");
+  } else {
+    ruby_eval("require 'kinput2_default'");
+  }
+  if (ruby_eval("global_variables.member?('$kanjiConv')") == Qfalse) {
+    fprintf(stderr, "Abort: KanjiConv was not initialized.\n");
+    exit (-1);
+  }
+  ruby_eval("kanjiConv = $kanjiConv");
+  TRACE(("RubyObjectClass initialized\n"));
+}
+
+static int
+InputEvent(w, event)
+Widget w;
+XEvent *event;
+{
+    RubyObject obj = (RubyObject)w;
+    char key_buf[200];
+    KeySym keysym;
+    int len, nbytes, functionalChar;
+
+    /* KeyPress以外は捨てる */
+    if (event->type != KeyPress /*&& event->type != KeyRelease*/) return 0;
+
+    /* 取りあえず文字に直してしまう */
+    key_buf[0] = '\0';
+    key_buf[1] = '\0';
+    key_buf[2] = '\0';
+    nbytes = XLookupString(event, key_buf, 20, &keysym, NULL);
+
+    if (keysym == XK_space && (event->xkey.state & ShiftMask)) {
+      convend(obj);
+      return 0;
+    }
+
+    /* ベルを鳴らすディスプレイの設定 */
+    displaybell = XtDisplayOfObject((Widget)obj);
+
+    /* かな漢字変換する */
+    {
+      VALUE pass;
+      printf ("key_buf: `%d'\n", key_buf[0]);
+      printf ("strlen(key_buf): `%d'\n", strlen(key_buf));
+      printf ("nbytes: `%d'\n", nbytes);
+      pass = ruby_evalf ("kanjiConv.inputEvent(%d, %d, %d)",
+			 key_buf[0], (int)keysym, (int)(event->xkey.state));
+      printf ("Input: done\n");
+
+      rubyDisplayPreEdit(obj);
+
+      return NUM2INT(pass); /* 1: pass the key / 0: trap the key */
+    }
+}
+
+
+static void
+rubyDialogDisplay(obj)
+RubyObject obj;
+{
+  ICAuxControlArg arg;
+
+  /* I'm not sure about Aux. */
+  if (ruby_eval("kanjiConv.dialog.visible") == Qfalse) {
+    if (ruby_eval("kanjiConv.dialog.call_open") == Qtrue &&
+	ruby_eval ("kanjiConv.dialog.text.length > 0") == Qtrue) {
+      printf ("Dialog: open\n");
+      arg.command = ICAuxStart;
+      XtCallCallbackList((Widget)obj, obj->inputConv.auxcallback,
+			 (XtPointer)&arg);
+      ruby_eval("kanjiConv.dialog.open_end");
+    }
+  } else { /* value_dialog_visible == true */
+    if (ruby_eval("kanjiConv.dialog.call_close") == Qtrue) {
+      printf ("Dialog: close\n");
+      arg.command = ICAuxEnd;
+      XtCallCallbackList((Widget)obj, obj->inputConv.auxcallback,
+			 (XtPointer)&arg);
+      ruby_eval("kanjiConv.dialog.close_end");
+      printf ("Dialog: close...done\n");
+    } else {
+      arg.command = ICAuxChange;
+      XtCallCallbackList((Widget)obj, obj->inputConv.auxcallback,
+			 (XtPointer)&arg);
+    }
+  }
+}
+
+static void
+rubySelectionEvent(obj)
+RubyObject obj;
+{
+  /*** Right ***/
+  if (ruby_eval("kanjiConv.selection.call_right") == Qtrue) {
+    moveSelection(obj, ICMoveRight);
+    ruby_eval("kanjiConv.selection.right_end");
+  }
+    
+  /*** Left ***/
+  if (ruby_eval("kanjiConv.selection.call_left") == Qtrue) {
+    moveSelection(obj, ICMoveLeft);
+    ruby_eval("kanjiConv.selection.left_end");
+  }
+
+  /*** Down ***/
+  if (ruby_eval("kanjiConv.selection.call_down") == Qtrue) {
+    moveSelection(obj, ICMoveDown);
+    ruby_eval("kanjiConv.selection.down_end");
+  }
+
+  /*** Up ***/
+  if (ruby_eval("kanjiConv.selection.call_up") == Qtrue) {
+    moveSelection(obj, ICMoveUp);
+    ruby_eval("kanjiConv.selection.up_end");
+  }
+
+  /*** Beginning Line ***/
+  if (ruby_eval("kanjiConv.selection.call_line_beginning") == Qtrue) {
+    moveSelection(obj, ICMoveLeftMost);
+    ruby_eval("kanjiConv.selection.line_beginning_end");
+  }
+
+  /*** End Line ***/
+  if (ruby_eval("kanjiConv.selection.call_line_end") == Qtrue) {
+    moveSelection(obj, ICMoveRightMost);
+    ruby_eval("kanjiConv.selection.line_end_end");
+  }
+
+  /*** Get Index ***/
+  {
+    ICSelectionControlArg arg;
+    arg.command = ICSelectionGet;
+    arg.u.current_item = -1;
+
+    XtCallCallbackList((Widget)obj, obj->inputConv.selectioncallback,
+		       (XtPointer)&arg);
+
+    if (arg.u.current_item >= 0) {
+      ruby_evalf ("kanjiConv.set_cand_index (%d)", arg.u.current_item);
+    }
+  }
+}
+
+static void
+moveSelection(obj, dir)
+RubyObject obj;
+int dir;
+{
+  ICSelectionControlArg arg;
+
+  arg.command = ICSelectionMove;
+  arg.u.dir = dir;
+  XtCallCallbackList((Widget)obj, obj->inputConv.selectioncallback,
+		     (XtPointer)&arg);
+}
+
+static void
+rubySelectionDisplay(obj)
+RubyObject obj;
+{
+  ICSelectionControlArg arg;
+
+  if (ruby_eval("kanjiConv.selection.call_open") == Qtrue) {
+    printf ("Selection: open\n");
+    arg.command = ICSelectionStart;
+    arg.u.selection_kind = ICSelectionCandidates;
+    XtCallCallbackList((Widget)obj, obj->inputConv.selectioncallback,
+		       (XtPointer)&arg);
+
+    /* set current item */
+    arg.command = ICSelectionSet;
+    arg.u.current_item = 0; /* INDEX of ITEM */
+    XtCallCallbackList((Widget)obj, obj->inputConv.selectioncallback,
+		       (XtPointer)&arg);
+
+    ruby_eval("kanjiConv.selection.open_end");
+  } else if (ruby_eval("kanjiConv.selection.call_close") == Qtrue) {
+    printf ("Selection: close\n");
+    arg.command = ICSelectionEnd;
+    arg.u.current_item = -1;
+    XtCallCallbackList((Widget)obj, obj->inputConv.selectioncallback,
+		       (XtPointer)&arg);
+    ruby_eval("kanjiConv.selection.close_end");
+  }
+}
+
+
+static void
+rubyDisplayPreEdit(obj)
+RubyObject obj;
+{
+    Widget w = (Widget)obj;
+    
+    if (ruby_eval("kanjiConv.call_fix") == Qtrue) {
+      fix(obj);
+    }
+
+    /* 入力モードをチェックする */
+/* #if 0 */
+/*     if (ks->info & KanjiModeInfo) { */
+/*       printf("modechangecallback\n"); */
+    XtCallCallbackList(w, obj->inputConv.modechangecallback,
+		       (XtPointer)NULL);
+/*     } */
+/* #endif */
+
+    rubyDialogDisplay(obj);
+    rubySelectionEvent(obj);
+    rubySelectionDisplay(obj);
+
+    XtCallCallbackList(w, obj->inputConv.textchangecallback,
+		       (XtPointer)NULL);
+}
+
+
+
+
+static ICString *
+GetMode(w)
+Widget w;
+{
+    rubyEUCtoICString (ruby_eval ("kanjiConv.modeline"), ruby_tmp_seg);
+    ruby_tmp_seg->attr = ICAttrNormalString;
+    return ruby_tmp_seg;
+}
+
+static int
+CursorPos(w, nsegp, ncharp)
+Widget w;
+Cardinal *nsegp;
+Cardinal *ncharp;
+{
+    /*
+    return value : =0 corsor ON  /    =1 OFF
+    nseg: >0 segment index / =0 no segment
+    nchar: number of chars; 'テs' == 2
+    */
+    *ncharp = NUM2INT(ruby_eval("kanjiConv.input.cursor"));
+    *nsegp  = 0;
+
+/*     printf ("CursorPos: nseg=%d, nchar=%d\n", (int)*nsegp, (int)*ncharp); */
+
+    return (*ncharp == 0) ? 1: 0;
+}
+
+static int
+NumSegments(w)
+Widget w;
+{
+    int num;
+    printf ("NumSegments\n");
+    num = NUM2INT(ruby_eval("kanjiConv.segment_length"));
+/*     printf ("NumSegments: num=%d\n", num); */
+    return num;
+}
+
+static ICString *
+GetSegment(w, n)
+Widget w;
+Cardinal n;
+{
+    RubyObject obj = (RubyObject)w;
+    static ICString seg;
+
+    printf("GetSegment\n");
+
+    rubyEUCtoICString (ruby_evalf ("kanjiConv.segment_word(%d)", n),
+		       ruby_tmp_seg);
+    if (ruby_evalf("kanjiConv.segment_status(%d) == :highlight", n) == Qtrue) {
+      ruby_tmp_seg->attr = ICAttrConverted | ICAttrCurrentSegment;
+    } else {
+      ruby_tmp_seg->attr = ICAttrNotConverted;
+    }
+    /* ICAttrConverted | ICAttrCurrentSegment : Inversion. */
+    /* |= ICAttrChanged : Non-Underline. */
+    return ruby_tmp_seg;
+}
+
+/* ARGSUSED */
+static int
+CompareSegment(w, seg1, seg2, n)
+Widget w;
+ICString *seg1;
+ICString *seg2;
+Cardinal *n;
+{
+    wchar *p, *q;
+    int len, nsame;
+    int result = 0;
+
+    printf("CompareSegment\n");
+
+    if (seg1->attr != seg2->attr) result |= ICAttrChanged;
+
+    len = seg1->nchars > seg2->nchars ? seg2->nchars : seg1->nchars;
+    nsame = 0;
+    p = (wchar *)seg1->data;
+    q = (wchar *)seg2->data;
+    while (nsame < len && *p++ == *q++) nsame++;
+
+    if (nsame != len || len != seg1->nchars || len != seg2->nchars)
+	result |= ICStringChanged;
+
+    if (n) *n = nsame;
+
+    return result;
+}
+
+static ICString *
+GetItemList(w, n)
+Widget w;
+Cardinal *n;
+{
+    RubyObject obj = (RubyObject)w;
+
+    printf("GetItemList\n");
+    rubyEUCArraytoICStringArray(ruby_eval("kanjiConv.cand_list"),
+				ruby_cand_list);
+    *n = ruby_cand_list->length;
+    return ruby_cand_list->array;
+}
+
+static int
+SelectItem(w, n)
+Widget w;
+int n;
+{
+
+  RubyObject obj = (RubyObject)w;
+  printf ("selectItem\n");
+  ruby_evalf("kanjiConv.selection_fix (%d)", n);
+  /* FIXME: Create new fix function in the feature. */
+  fix (obj);
+  XtCallCallbackList(w, obj->inputConv.textchangecallback,
+		     (XtPointer)NULL);
+  return 0;
+}
+
+static int
+ConvertedString(w, encoding, format, length, string)
+Widget w;
+Atom *encoding;
+int *format;
+int *length;
+XtPointer *string;
+{
+    RubyObject obj = (RubyObject)w;
+    wchar *wbuf, *wp;
+    int len, wlen;
+    extern int convJWStoCT();
+
+    /* メモリの解放は自動的に行われる. str を直接書き換えてはいけない. */
+    unsigned char *str = STR2CSTR(ruby_eval("kanjiConv.value_fixed"));
+
+    printf("ConvertedString\n");
+
+    wbuf = XtMalloc((strlen(str) + 1) * sizeof(wchar));
+    euc2wcs(str, strlen(str), wbuf);
+    wlen = wstrlen(wbuf);
+
+    /*
+     * Ruby オブジェクトは COMPOUND_TEXT エンコーディングしかサポートしない
+     * COMPOUND_TEXT に変換する
+     */
+    *encoding = XA_COMPOUND_TEXT(XtDisplayOfObject((Widget)obj));
+    *format = 8;
+
+    /* COMPOUND_TEXT は \r が送れないので \n に変換しておく */
+    for (wp = wbuf; *wp != 0; wp++) {
+	if (*wp == '\r') *wp = '\n';
+    }
+
+    *length = len = convJWStoCT(wbuf, (unsigned char *)NULL, 0);
+    *string = XtMalloc(len + 1);
+    (void)convJWStoCT(wbuf, (unsigned char *)*string, 0);
+
+    XtFree(wbuf);
+
+    return 0;
+}
+
+static int
+ClearConversion(w)
+Widget w;
+{
+  ruby_eval ("kanjiConv.clear");
+  return 0;
+}
+
+static ICString *
+GetAuxSegments(w, n, ns, nc)
+Widget w;
+Cardinal *n, *ns, *nc;
+{
+  /* I'm not sure about this function's purpose. */
+  /* n  => ngseg ; number of segments (1 <= n <= 3). */
+  /* ns => nseg  ; index of reversed segment (0 or 1). */
+  /* nc => nchar ; length of current segment??? */ 
+  printf ("GetAuxSegments\n");
+
+  if ((ruby_eval ("kanjiConv.dialog.visible") == Qtrue ||
+       ruby_eval ("kanjiConv.dialog.call_open") == Qtrue) &&
+      ruby_eval ("kanjiConv.dialog.text.length > 0") == Qtrue) {
+    if (n) {
+      *n = 1;
+    }
+
+    if (ns) {
+      *ns = 0;
+    }
+
+    rubyEUCtoICString (ruby_eval ("kanjiConv.dialog.text"),
+		       ruby_tmp_seg);
+    ruby_tmp_seg->attr = ICAttrConverted;
+
+    if (nc) {
+      *nc = ruby_tmp_seg->nchars;
+    }
+
+    return ruby_tmp_seg;
+  } else {
+    if (n) {
+      *n = 0;
+    }
+    if (ns) {
+      *ns = 0;
+    }
+    if (nc) {
+      *nc = 0;
+    }
+    return NULL;
+  }
+}
+
+/* ARGSUSED */
+static void
+Initialize(req, new, args, num_args)
+Widget req;
+Widget new;
+ArgList args;
+Cardinal *num_args;
+{
+    RubyObject obj = (RubyObject)new;
+
+    obj->ruby.selectionending = False;
+    obj->ruby.textchanged = False;
+    obj->ruby.symbollist = SymbolList;
+    obj->ruby.numsymbols = NumSymbols;
+    obj->ruby.cursymbol = 0;
+    obj->ruby.candlist = NULL;
+    obj->ruby.candlistsize = 0;
+    obj->ruby.numcand = 0;
+    obj->ruby.lastTextLengthIsZero = False;
+      
+    addObject(obj);
+}
+
+static int
+bell()
+{
+  if (displaybell) {
+    XBell(displaybell, 0);
+  }
+  return 0;
+}
+
+static int nRubyContexts = 0;
+
+static void
+Destroy(w)
+Widget w;
+{
+    RubyObject obj = (RubyObject)w;
+    wchar buf[512];
+    int i;
+    
+    if (obj->ruby.candlist) {
+      for (i = 0 ; i < obj->ruby.candlistsize ; i++) {
+	if ((obj->ruby.candlist + i)->data) {
+	  XtFree((obj->ruby.candlist + i)->data);
+	}
+      }
+
+      XtFree((char *)obj->ruby.candlist);
+    }
+
+    /* Ruby 用終了処理をここに書く */
+
+    deleteObject(obj);
+}
+
+static Boolean
+SetValues(cur, req, wid, args, num_args)
+Widget cur;
+Widget req;
+Widget wid;
+ArgList args;
+Cardinal *num_args;
+/* ARGSUSED */
+{
+    RubyObject old = (RubyObject)cur;
+    RubyObject new = (RubyObject)wid;
+
+    return False;	     
+}
+
+static void
+fix(obj)
+RubyObject obj;
+{
+    /* 確定の処理 */
+    XtCallCallbackList((Widget)obj, obj->inputConv.fixcallback,
+		       (XtPointer)NULL);
+    ruby_eval("kanjiConv.fix_end");
+}
+
+static void
+convend(obj)
+RubyObject obj;
+{
+    XtCallCallbackList((Widget)obj, obj->inputConv.endcallback,
+		       (XtPointer)NULL);
+    ruby_eval("kanjiConv.reset");
+}
+
+/*
+ * keeping list of objects
+ */
+typedef struct _oblist_ {
+    RubyObject obj;
+    struct _oblist_ *next;
+} ObjRec;
+
+static ObjRec *ObjList = NULL;
+
+static void
+addObject(obj)
+RubyObject obj;
+{
+    ObjRec *objp = XtNew(ObjRec);
+
+    objp->obj = obj;
+    objp->next = ObjList;
+    ObjList = objp;
+}
+
+static void
+deleteObject(obj)
+RubyObject obj;
+{
+    ObjRec *objp, *objp0;
+
+    for (objp0 = NULL, objp = ObjList;
+	 objp != NULL;
+	 objp0 = objp, objp = objp->next) {
+	if (objp->obj == obj) {
+	    if (objp0 == NULL) {
+		ObjList = objp->next;
+	    } else {
+		objp0->next = objp->next;
+	    }
+	    XtFree((char *)objp);
+	    return;
+	}
+    }
+}
+
+/* ARGSUSED */
+static int
+GetTriggerKeys(w, keys_return)
+Widget w;
+ICTriggerKey **keys_return;
+{
+  /* 何をする関数なのか不明 (komatsu) */
+
+  *keys_return = NULL;
+  return 0;
+}
+
+/* ARGSUSED */
+
+
+/*
+ * int ICGetPreeditString(Widget object, int segn, int offset,
+ *                        Atom *encoding, int *format,
+ *                        int *length, XtPointer *string)
+ *      変換途中の segn 番目の セグメントの offset 文字からのテキストを
+ *      string に返す
+ *      encoding には、テキストのエンコーディングを指定しておく
+ *      ただしこれは単なるリクエストであって、変換オブジェクトは
+ *      別のエンコーディングで返してもよい
+ *      encoding には実際のエンコーディングが返される
+ *      変換オブジェクトは少なくとも COMPOUND_TEXT エンコーディングは
+ *      サポートしなくてはならない
+ *      format には 8/16/32 のいずれか、length は string のエレメント数が
+ *      それぞれ返される
+ *      テキストの領域は malloc されているのでこの関数を呼んだ側で
+ *      free しなければならない
+ *      変換テキストがない時やエラーの場合には -1、そうでなければ 0 が
+ *      関数の値として返される
+ */
+/* まだ, 未検討 (komatsu) */
+static int
+PreeditString(w, segn, offset, encoding, format, length, string)
+Widget w;
+int segn;
+int offset;
+Atom *encoding;
+int *format;
+int *length;
+XtPointer *string;
+{
+    RubyObject obj = (RubyObject)w;
+
+    return -1;
+}
+
+/* ARGSUSED */
+static int
+StatusString(w, encoding, format, length, string, nchars)
+Widget w;
+Atom *encoding;
+int *format;
+int *length;
+XtPointer *string;
+int *nchars;
+{
+    ICString *seg;
+    wchar *wbuf, *wp;
+    int len, wlen;
+    extern int convJWStoCT();
+
+    printf("StatusString\n");
+
+    seg = GetMode(w);
+    if (seg == NULL) {
+	*length = *nchars = 0;
+	return -1;
+    }
+
+    wlen = seg->nchars;
+    if (wlen <= 0) {
+	*length = *nchars = 0;
+	return -1;
+    }
+
+    /*
+     * data に入っている変換テキストは null ターミネートされていないかも
+     * しれないので、まずコピーして null ターミネートする
+     */
+    wbuf = (wchar *)XtMalloc((wlen + 1) * sizeof(wchar));
+    (void)bcopy(seg->data, (char *)wbuf, sizeof(wchar) * wlen);
+    wbuf[wlen] = 0;
+
+    /*
+     * Ruby オブジェクトは COMPOUND_TEXT エンコーディングしかサポートしない
+     * COMPOUND_TEXT に変換する
+     */
+    *encoding = XA_COMPOUND_TEXT(XtDisplayOfObject(w));
+    *format = 8;
+
+    /* COMPOUND_TEXT は \r が送れないので \n に変換しておく */
+    for (wp = wbuf; *wp != 0; wp++) {
+	if (*wp == '\r') *wp = '\n';
+    }
+
+    *length = len = convJWStoCT(wbuf, (unsigned char *)NULL, 0);
+    *string = XtMalloc(len + 1);
+    (void)convJWStoCT(wbuf, (unsigned char *)*string, 0);
+    *nchars = seg->nchars;
+
+    /* wbuf を free しておく */
+    XtFree((char *)wbuf);
+
+    return 0;
+}
+
+/***
+ic_str->nbytes が 0 の場合 ic_str->data は自動的に確保 (XtMalloc) される.
+ 0 以外の場合 ic_str->data は (XtRealloc) される.
+ */
+static void
+rubyEUCtoICString(ruby_str, ic_str)
+VALUE ruby_str;
+ICString *ic_str;
+{
+  unsigned char *euc_str;
+  int euc_len;
+  wchar *wc_str;
+  
+/*   printf("String_Len: %d\n", RSTRING(ruby_str)->len); */
+
+  euc_str = STR2CSTR(ruby_str);
+  euc_len = strlen(euc_str);
+
+  if (ic_str->nbytes == 0) {
+    wc_str = (wchar *)XtMalloc((euc_len + 1) * sizeof(wchar));
+  } else {
+    wc_str = (wchar *)XtRealloc(ic_str->data, (euc_len + 1) * sizeof(wchar));
+  }
+  euc2wcs(euc_str, euc_len, wc_str);
+
+  ic_str->data   = (char *)wc_str;
+  ic_str->nchars = wstrlen(wc_str);
+  ic_str->nbytes = (euc_len + 1) * sizeof(wchar);
+  ic_str->attr   = ICAttrNotConverted;
+}
+
+static void
+rubyEUCArraytoICStringArray(ruby_str_ary, ic_str_ary)
+VALUE ruby_str_ary;
+ICStringArray *ic_str_ary;
+{
+  VALUE ruby_str;
+  int i, array_length;
+  ICString ic_str;
+
+  array_length = RARRAY(ruby_str_ary)->len;
+  if ((ic_str_ary->length) < array_length) {
+    ic_str_ary->array = (ICString *)XtRealloc((char *)ic_str_ary->array,
+					      array_length * sizeof(ICString));
+    for (i = ic_str_ary->length; i < array_length; i++) {
+/*       ic_str_ary->array[i] = (ICString *)XtMalloc(1 * sizeof(ICString)); */
+      ic_str_ary->array[i].nbytes = 0;
+    }
+  }
+  ic_str_ary->length = array_length;
+
+/*   printf("array_length: %d\n", array_length); */
+
+  for (i = 0; i < array_length; i++) {
+    rubyEUCtoICString(rb_ary_entry(ruby_str_ary, i), &(ic_str_ary->array[i]));
+  }
+}