diff lib/OnConv.c @ 0:92745d501b9a

initial import from kinput2-v3.1
author Yoshiki Yazawa <yaz@honeyplanet.jp>
date Mon, 08 Mar 2010 04:44:30 +0900
parents
children e55ccba56891 07a41a882b14
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/OnConv.c	Mon Mar 08 04:44:30 2010 +0900
@@ -0,0 +1,1442 @@
+#ifndef lint
+static char *rcsid = "$Id: OnConv.c,v 10.9 1999/05/19 08:52:42 ishisone Exp $";
+#endif
+/*
+ * Copyright (c) 1990  Software Research Associates, Inc.
+ * Copyright (c) 1999  Kazuki YASUMATSU
+ *
+ * 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
+ * Author:  Kazuki YASUMATSU (Kazuki.Yasumatsu@fujixerox.co.jp)
+ */
+
+
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+#include <X11/Xmu/Atoms.h>
+#if XtSpecificationRelease > 4
+#include <X11/Xfuncs.h>
+#endif
+#include "CachedAtom.h"
+#include "AsyncErr.h"
+#include "OnConvP.h"
+#include "InputConv.h"
+#include "ConvDisp.h"
+#include "CandPanel.h"
+#include "AuxPanel.h"
+#include "ICLabel.h"
+
+#define DEBUG_VAR debug_OnTheSpotConversion
+#include "DebugPrint.h"
+
+/*- resource table -*/
+static XtResource resources[] = {
+#define offset(field) XtOffset(OnTheSpotConversionWidget, onthespot.field)
+    { XtNpreeditStartCallback, XtCCallback, XtRCallback, sizeof(XtCallbackList),
+	offset(preeditstartcallback), XtRCallback, (XtPointer)NULL },
+    { XtNpreeditDoneCallback, XtCCallback, XtRCallback, sizeof(XtCallbackList),
+	offset(preeditdonecallback), XtRCallback, (XtPointer)NULL },
+    { XtNpreeditDrawCallback, XtCCallback, XtRCallback, sizeof(XtCallbackList),
+	offset(preeditdrawcallback), XtRCallback, (XtPointer)NULL },
+    { XtNpreeditCaretCallback, XtCCallback, XtRCallback, sizeof(XtCallbackList),
+	offset(preeditcaretcallback), XtRCallback, (XtPointer)NULL },
+    { XtNstatusStartCallback, XtCCallback, XtRCallback, sizeof(XtCallbackList),
+	offset(statusstartcallback), XtRCallback, (XtPointer)NULL },
+    { XtNstatusDoneCallback, XtCCallback, XtRCallback, sizeof(XtCallbackList),
+	offset(statusdonecallback), XtRCallback, (XtPointer)NULL },
+    { XtNstatusDrawCallback, XtCCallback, XtRCallback, sizeof(XtCallbackList),
+	offset(statusdrawcallback), XtRCallback, (XtPointer)NULL },
+    { XtNfeedbackAttributes, XtCFeedbackAttributes,
+	XtRFeedbackAttributes, sizeof(FeedbackAttributes),
+	offset(feedbackattrs), XtRString, (XtPointer)"U,,R,H" },
+#undef offset
+};
+
+/*- default translations -*/
+static char translations[] = "<Key>: to-inputobj()";	/* same as superclass's	*/
+
+/*- declarations of local structures -*/
+typedef struct {
+    int		attrs_length;
+    int		attrs_limit;
+    unsigned long *attrs_buffer;
+} AttributeBuffer;
+
+/*- declarations of static functions -*/
+static void ClassInitialize();
+static void Initialize();
+static void Destroy();
+static Boolean SetValues();
+
+static void ConversionStartup();
+static void ConversionFinish();
+static void ChangeAttributes();
+static void ChangeFocus();
+
+static void StringToFeedbackAttrs();
+
+static Widget CreateSelectionWidget();
+
+static void UpdateText();
+static void CommitText();
+static void UpdateMode();
+static void SelectionControl();
+
+static void SelectionStart();
+static void LocateSelectionPopup();
+static void SelectionEnd();
+static void SelectionSet();
+static void SelectionGet();
+static void SelectionMove();
+
+static Widget CreateAuxWidget();
+static void AuxControl();
+static void AuxStart();
+static void AuxEnd();
+static void AuxChange();
+static void LocateAuxPopup();
+
+static void SelectionSelected();
+
+static Boolean SafeGetWindowAttributes();
+static void MoveShell();
+static Window getToplevelWindow();
+static void setTransientFor();
+static void allocDisplaySegments();
+static void freeDisplaySegment();
+static void clearAllDisplaySegments();
+static void copyString();
+static void freeString();
+static AttributeBuffer *allocAttributeBuffer();
+static void destroyAttributeBuffer();
+static void addAttributeBuffer();
+static unsigned long attrToFeedback();
+static void CBPreeditStart();
+static void CBPreeditDone();
+static void CBPreeditDraw();
+static void CBPreeditCaret();
+static void CBStatusStart();
+static void CBStatusDone();
+static void CBStatusDraw();
+
+/*- composite-extension rec: for enabling non-widget children -*/
+static CompositeClassExtensionRec CompositeExtension = {
+    /* next_extension		*/	NULL,
+    /* record_type		*/	NULLQUARK,
+    /* version			*/	XtCompositeExtensionVersion,
+    /* record_size		*/	sizeof(CompositeClassExtensionRec),
+    /* accept_objects		*/	True,
+};
+
+/*- onTheSpotConversionClass record -*/
+OnTheSpotConversionClassRec onTheSpotConversionClassRec = {
+  { /* core fields */
+    /* superclass		*/	(WidgetClass)&conversionControlClassRec,
+    /* class_name		*/	"OnTheSpotConversion",
+    /* widget_size		*/	sizeof(OnTheSpotConversionRec),
+    /* class_initialize		*/	ClassInitialize,
+    /* class_part_initialize	*/	NULL,
+    /* class_inited		*/	FALSE,
+    /* initialize		*/	Initialize,
+    /* initialize_hook		*/	NULL,
+    /* realize			*/	XtInheritRealize,
+    /* actions			*/	NULL,
+    /* num_actions		*/	0,
+    /* resources		*/	resources,
+    /* num_resources		*/	XtNumber(resources),
+    /* xrm_class		*/	NULLQUARK,
+    /* compress_motion		*/	TRUE,
+    /* compress_exposure	*/	TRUE,
+    /* compress_enterleave	*/	TRUE,
+    /* visible_interest		*/	FALSE,
+    /* destroy			*/	Destroy,
+    /* resize			*/	XtInheritResize,
+    /* expose			*/	NULL,
+    /* set_values		*/	SetValues,
+    /* set_values_hook		*/	NULL,
+    /* set_values_almost	*/	XtInheritSetValuesAlmost,
+    /* get_values_hook		*/	NULL,
+    /* accept_focus		*/	NULL,
+    /* version			*/	XtVersion,
+    /* callback_private		*/	NULL,
+    /* tm_table			*/	translations,
+    /* query_geometry		*/	XtInheritQueryGeometry,
+    /* display_accelerator	*/	XtInheritDisplayAccelerator,
+    /* extension		*/	NULL
+  },
+  { /* composite fields */
+    /* geometry_manager		*/	XtInheritGeometryManager,
+    /* change_managed		*/	XtInheritChangeManaged,
+    /* insert_child		*/	XtInheritInsertChild,
+    /* delete_child		*/	XtInheritDeleteChild,
+    /* extension		*/	(XtPointer)&CompositeExtension,
+  },
+  { /* shell fields */
+    /* extension		*/	NULL
+  },
+  { /* wm_shell fields */
+    /* extension		*/	NULL
+  },
+  { /* vendor_shell fields */
+    /* extension		*/	NULL
+  },
+  { /* transient_shell fields */
+    /* extension		*/	NULL
+  },
+  { /* conversionControl fields */
+    /* Startup			*/	ConversionStartup,
+    /* Finish			*/	ConversionFinish,
+    /* ChangeAttributes		*/	ChangeAttributes,
+    /* ChangeFocus		*/	ChangeFocus,
+    /* TextChange		*/	UpdateText,
+    /* Fix			*/	CommitText,
+    /* ModeChange		*/	UpdateMode,
+    /* SelectionControl		*/	SelectionControl,
+    /* AuxControl		*/	AuxControl,
+  },
+  { /* onTheSpotConversion fields */
+    /* empty			*/	0
+  },
+};
+
+WidgetClass onTheSpotConversionWidgetClass = (WidgetClass)&onTheSpotConversionClassRec;
+
+/*
+ *+ Core class method
+ */
+
+/*- ClassInitialize: class initializer -*/
+/* ARGSUSED */
+static void
+ClassInitialize()
+{
+    /* add String -> FeedbackAttributes converter */
+    XtAddConverter(XtRString, XtRFeedbackAttributes, StringToFeedbackAttrs,
+		   (XtConvertArgList)NULL, (Cardinal)0);
+}
+
+/*- Initialize: initalize method -*/
+/* ARGSUSED */
+static void
+Initialize(req, new, args, num_args)
+Widget req;
+Widget new;
+ArgList args;
+Cardinal *num_args;
+{
+    OnTheSpotConversionWidget ocw = (OnTheSpotConversionWidget)new;
+
+    (void)CreateSelectionWidget(ocw);
+    (void)CreateAuxWidget(ocw);
+
+    ocw->onthespot.dispsegments = NULL;
+    ocw->onthespot.numsegments = 0;
+    ocw->onthespot.dispsegmentsize = 0;
+    ocw->onthespot.candlist = NULL;
+    ocw->onthespot.numcands = 0;
+    ocw->onthespot.selectionpoppedup = False;
+    ocw->onthespot.auxpoppedup = False;
+    ocw->onthespot.lastcaret = 0;
+    ocw->onthespot.fixnotify = False;
+}
+
+/*- Destroy: destroy method -*/
+static void
+Destroy(w)
+Widget w;
+{
+    OnTheSpotConversionWidget ocw = (OnTheSpotConversionWidget)w;
+
+    /* $B%G%#%9%W%l%$%;%0%a%s%H$NNN0h$r2rJ|(B */
+    if (ocw->onthespot.dispsegments) {
+	DisplaySegment *dsp = ocw->onthespot.dispsegments;
+	int i;
+
+	for (i = 0; i < ocw->onthespot.numsegments; i++) {
+	    freeString(&dsp[i].seg);
+	}
+	XtFree((char *)dsp);
+    }
+}
+
+/*- SetValues: setvalues method -*/
+/* ARGSUSED */
+static Boolean
+SetValues(cur, req, new, args, num_args)
+Widget cur;
+Widget req;
+Widget new;
+ArgList args;
+Cardinal *num_args;
+{
+    /* OnTheSpotConversionWidget ocw = (OnTheSpotConversionWidget)new; */
+    return False;
+}
+
+/*
+ *+ ConversionControl class method
+ */
+
+/*- ConversionStartup: class specific conversion startup -*/
+static void
+ConversionStartup(widget, valuemask, value)
+Widget widget;
+unsigned long valuemask;
+ConversionAttributes *value;
+{
+    OnTheSpotConversionWidget ocw = (OnTheSpotConversionWidget)widget;
+    Widget inputobj = ocw->ccontrol.inputobj;
+    Window toplevel;
+
+    TRACE(("OnTheSpot:ConversionStartup()\n"));
+
+    /* $BFbIt$N%P%C%U%!$r%/%j%"$9$k(B */
+    clearAllDisplaySegments(ocw);
+
+    /* WM_TRANSIENT_FOR $B%W%m%Q%F%#$r@5$7$/%;%C%H$9$k(B */
+    toplevel = getToplevelWindow(XtDisplay(widget),
+				 ocw->ccontrol.clientwindow);
+    setTransientFor(ocw->onthespot.selectionshell, toplevel);
+    setTransientFor(ocw->onthespot.auxshell, toplevel);
+
+    /*
+     * OnTheSpotConvesion $B$N(B widget $B<+BN$O%]%C%W%"%C%W$5$;$J$$$,!"(B
+     * $B%P%C%/%(%s%I%?%$%W$N;~$K$O%/%i%$%"%s%H$,$3$N(B widget $B$N(B
+     * $B%&%#%s%I%&$KBP$7$F%$%Y%s%H$rAw$k$N$G(B Realize $B$@$1$7$F$*$/(B
+     */
+    if (!XtIsRealized(widget)) {
+	Arg args[2];
+
+	XtSetArg(args[0], XtNwidth, 1);
+	XtSetArg(args[1], XtNheight, 1);
+	XtSetValues(widget, args, 2);
+	XtRealizeWidget(widget);
+    }
+
+    ocw->onthespot.lastcaret = 0;
+    ocw->onthespot.fixnotify = False;
+
+    /* $B%9%F!<%?%9$r99?7$9$k(B */
+    UpdateMode(widget);
+
+    /* $B%W%l%(%G%#%C%H$r3+;O$9$k(B */
+    CBPreeditStart(widget);
+}
+
+/*- ConversionFinish: class specific conversion finish -*/
+/* ARGSUSED */
+static void
+ConversionFinish(w)
+Widget w;
+{
+    OnTheSpotConversionWidget ocw = (OnTheSpotConversionWidget)w;
+    Atom encoding = XA_COMPOUND_TEXT(XtDisplayOfObject(w));
+    int format = 8;
+
+    if (!ocw->onthespot.fixnotify) {
+	/* $B3NDj$7$F$$$J$$(B */
+	DisplaySegment *dseg = ocw->onthespot.dispsegments;
+	int i, len = 0;
+	for (i = 0; i < ocw->onthespot.numsegments; i++, dseg++) {
+	    len += dseg->seg.nchars;
+	}
+	if (len > 0) {
+	    /* $B%W%l%(%G%#%C%H%P%C%U%!$N>C5n(B */
+	    unsigned long attr = 0;
+	    CBPreeditDraw(ocw, 0, 0, len, encoding, format, 0, (XPointer)"",
+			  0, &attr);
+	}
+    }
+
+    /* $B%W%l%(%G%#%C%H$r=*N;$9$k(B */
+    CBPreeditDone(w);
+
+    /* $B%9%F!<%?%9$r99?7(B($B=i4|2=(B)$B$9$k(B */
+    CBStatusDraw(ocw, encoding, format, 0, (XPointer)"", 0);
+
+    if (ocw->onthespot.selectionpoppedup) {
+	XtPopdown(ocw->onthespot.selectionshell);
+	ocw->onthespot.selectionpoppedup = False;
+    }
+    if (ocw->onthespot.auxpoppedup) {
+	XtPopdown(ocw->onthespot.auxshell);
+	ocw->onthespot.auxpoppedup = False;
+    }
+}
+
+/*- ChangeAttributes: class specific conversion attribute change routine -*/
+/* ARGSUSED */
+static void
+ChangeAttributes(w, valuemask, value)
+Widget w;
+unsigned long valuemask;
+ConversionAttributes *value;
+{
+    /* do nothing */
+}
+
+/*- ChangeFocus: class specific conversion attribute change routine -*/
+static void
+ChangeFocus(w, set)
+Widget w;
+int set;
+{
+    if (set) {
+	UpdateMode(w);
+    } else {
+#if 0
+	/* $B%U%)!<%+%9$r<:$C$?>l9g$K$O2?$b$7$J$$(B */
+	OnTheSpotConversionWidget ocw = (OnTheSpotConversionWidget)w;
+	Atom encoding = XA_COMPOUND_TEXT(XtDisplayOfObject(w));
+	int format = 8;
+
+	CBStatusDraw(ocw, encoding, format, 0, (XPointer)"", 0);
+#endif
+    }
+}
+
+/*
+ *+ resource converter
+ */
+
+/*- StringToFeedbackAttrs: string to feedback attiributes converter -*/
+static void
+StringToFeedbackAttrs(args, num_args, from, to)
+XrmValue *args;
+Cardinal *num_args;
+XrmValue *from;
+XrmValue *to;
+{
+    char *s = (char *)from->addr;
+    int idx;
+    int invalid = 0;
+    static FeedbackAttributes fba;
+
+    for (idx = 0; idx < 4; idx++) fba.feedbacks[idx] = 0;
+
+    for (idx = 0; idx < 4; idx++) {
+	int c;
+	unsigned long fb = 0;
+
+	while ((c = *s++) != ',' && c != '\0') {
+	    switch (c) {
+	    case 'R': case 'r': fb |= XIMReverse; break;
+	    case 'U': case 'u':	fb |= XIMUnderline; break;
+	    case 'H': case 'h': fb |= XIMHighlight; break;
+	    case 'P': case 'p': fb |= XIMPrimary; break;
+	    case 'S': case 's': fb |= XIMSecondary; break;
+	    case 'T': case 't': fb |= XIMTertiary; break;
+	    case ' ': case '\t':
+		break;
+	    default:
+		invalid++;
+		break;
+	    }
+	}
+	fba.feedbacks[idx] = fb;
+	if (c == '\0') break;
+    }
+
+    if (invalid) {
+	XtStringConversionWarning((char *)from->addr, XtRFeedbackAttributes);
+    }
+    to->size = sizeof(fba);
+    to->addr = (caddr_t)&fba;
+}
+
+/*
+ *+ sub-widget creation
+ */
+
+/*- CreateSelectionWidget: create selection widget for selecting candidates -*/
+static Widget
+CreateSelectionWidget(ocw)
+OnTheSpotConversionWidget ocw;
+{
+    Widget shell, sel;
+
+    /* set width/height so that XtRealizeWidget() doesn't cause error */
+    shell = XtVaCreatePopupShell("selectionShell",
+				 transientShellWidgetClass,
+				 (Widget)ocw,
+				 XtNwidth, 1,
+				 XtNheight, 1,
+				 NULL);
+    ocw->onthespot.selectionshell = shell;
+
+    sel = XtCreateManagedWidget("selection", candidatePanelWidgetClass,
+				shell, NULL, 0);
+    (void)XtCreateWidget("display", ocw->ccontrol.displayobjclass, sel,
+			 NULL, 0);
+    XtAddCallback(sel, XtNcallback, SelectionSelected, (XtPointer)ocw);
+    XtInstallAccelerators(sel, (Widget)ocw);
+
+    ocw->onthespot.selectionwidget = sel;
+
+    return shell;
+}
+
+/*- CreateAuxWidget: create aux widget for display auxiliary data -*/
+static Widget
+CreateAuxWidget(ocw)
+OnTheSpotConversionWidget ocw;
+{
+    Widget shell, sel;
+
+    /* set width/height so that XtRealizeWidget() doesn't cause error */
+    shell = XtVaCreatePopupShell("auxShell",
+				 transientShellWidgetClass,
+				 (Widget)ocw,
+				 XtNwidth, 1,
+				 XtNheight, 1,
+				 XtNallowShellResize, True,
+				 NULL);
+    ocw->onthespot.auxshell = shell;
+
+    sel = XtCreateManagedWidget("aux", auxPanelWidgetClass,
+				shell, NULL, 0);
+    (void)XtCreateWidget("display", ocw->ccontrol.displayobjclass, sel,
+			 NULL, 0);
+    XtAddCallback(sel, XtNcallback, SelectionSelected, (XtPointer)ocw);
+    XtInstallAccelerators(sel, (Widget)ocw);
+
+    ocw->onthespot.auxwidget = sel;
+
+    return shell;
+}
+
+/*
+ *+ inputobject callback
+ */
+
+/*- UpdateText: update text -*/
+static void
+UpdateText(w)
+Widget w;
+{
+    OnTheSpotConversionWidget ocw = (OnTheSpotConversionWidget)w;
+    Widget inputobj = ocw->ccontrol.inputobj;
+    int nnew = ICNumSegments(inputobj);
+    int nold = ocw->onthespot.numsegments;
+    FeedbackAttributes *fba = &ocw->onthespot.feedbackattrs;
+    Cardinal cseg, caret;
+    ICString *newseg;
+    DisplaySegment *dseg;
+    Boolean changed;
+    int chgseg, chgoffset;
+    int oldlen;
+    AttributeBuffer *buffer;
+    int i;
+    int diff;
+    Cardinal nsame;
+
+    TRACE(("OnTheSpotConversion:UpdateText() nnew=%d\n", nnew));
+
+    ocw->onthespot.fixnotify = False;
+
+    if (!ICCursorPos(inputobj, &cseg, &caret)) {
+	cseg = nnew;
+	caret = 0;
+    }
+
+    allocDisplaySegments(ocw, nnew);
+
+    changed = False;
+    chgseg = chgoffset = 0;
+    oldlen = 0;
+    buffer = allocAttributeBuffer();
+    for (i = 0, dseg = ocw->onthespot.dispsegments; i < nnew; i++, dseg++) {
+	newseg = ICGetSegment(inputobj, i);
+	if (i < cseg) {
+	    caret += newseg->nchars;
+	}
+	if (i >= nold) {
+	    copyString(newseg, &dseg->seg);
+	    addAttributeBuffer(buffer, inputobj, newseg, 0, fba);
+	    if (!changed) {
+		chgseg = i;
+		chgoffset = 0;
+		changed = True;
+	    }
+	} else {
+	    oldlen += dseg->seg.nchars;
+	    diff = ICCompareSegment(inputobj, newseg, &dseg->seg, &nsame);
+	    switch (diff) {
+	    case ICSame:
+		if (changed) {
+		    addAttributeBuffer(buffer, inputobj, newseg, 0, fba);
+		}
+		break;
+	    case ICAttrChanged:
+		dseg->seg.attr = newseg->attr;
+		addAttributeBuffer(buffer, inputobj, newseg, 0, fba);
+		if (!changed) {
+		    chgseg = i;
+		    chgoffset = 0;
+		    changed = True;
+		}
+		break;
+	    case ICStringChanged:
+		freeString(&dseg->seg);
+		copyString(newseg, &dseg->seg);
+		if (!changed) {
+		    addAttributeBuffer(buffer, inputobj, newseg, nsame, fba);
+		    chgseg = i;
+		    chgoffset = nsame;
+		    changed = True;
+		}
+		else {
+		    addAttributeBuffer(buffer, inputobj, newseg, 0, fba);
+		}
+		break;
+	    default: /* ICAttrChanged | ICStringChanged */
+		freeString(&dseg->seg);
+		copyString(newseg, &dseg->seg);
+		addAttributeBuffer(buffer, inputobj, newseg, 0, fba);
+		if (!changed) {
+		    chgseg = i;
+		    chgoffset = 0;
+		    changed = True;
+		}
+		break;
+	    }
+	}
+    }
+
+    for (; i < nold; i++, dseg++) {
+	oldlen += dseg->seg.nchars;
+	if (!changed) {
+	    chgseg = i;
+	    chgoffset = 0;
+	    changed = True;
+	}
+	freeDisplaySegment(dseg);
+    }
+
+    ocw->onthespot.numsegments = nnew;
+
+    if (!changed) {
+	if (ocw->onthespot.lastcaret != caret) {
+	    CBPreeditCaret(ocw, caret);
+	}
+    }
+    else { /* changed */
+	Atom encoding = ocw->ccontrol.textencoding;
+	int format;
+	int length;
+	XtPointer string;
+
+	if (ICGetPreeditString(inputobj, chgseg, chgoffset, &encoding, &format,
+			       &length, &string) == 0) {
+
+	    dseg = ocw->onthespot.dispsegments;
+	    for (i = 0; i < chgseg; i++, dseg++) {
+		chgoffset += dseg->seg.nchars;
+	    }
+	    CBPreeditDraw(ocw, caret, chgoffset, oldlen - chgoffset,
+			  encoding, format, length, string,
+			  buffer->attrs_length, buffer->attrs_buffer);
+
+	    /* string $B$r(B free $B$7$F$*$/(B */
+	    XtFree((char *)string);
+	}
+    }
+
+    ocw->onthespot.lastcaret = caret;
+
+    /* buffer $B$r(B destroy $B$7$F$*$/(B */
+    destroyAttributeBuffer(buffer);
+}
+
+/*- CommitText: commit text -*/
+static void
+CommitText(w, arg)
+Widget w;
+CCTextCallbackArg *arg;
+{
+    OnTheSpotConversionWidget ocw = (OnTheSpotConversionWidget)w;
+    DisplaySegment *dseg;
+    int i, len;
+
+    dseg = ocw->onthespot.dispsegments;
+    len = 0;
+    for (i = 0; i < ocw->onthespot.numsegments; i++, dseg++) {
+	len += dseg->seg.nchars;
+    }
+    if (len > 0) {
+	/* $B%W%l%(%G%#%C%H%P%C%U%!$N>C5n(B */
+	Atom encoding = XA_COMPOUND_TEXT(XtDisplayOfObject(w));
+	int format = 8;
+	unsigned long attr = 0;
+	CBPreeditDraw(ocw, 0, 0, len, encoding, format, 0, (XPointer)"",
+		      0, &attr);
+    }
+    /* $BFbIt$N%P%C%U%!$r%/%j%"$9$k(B */
+    clearAllDisplaySegments(ocw);
+    ocw->onthespot.lastcaret = 0;
+
+    XtCallCallbackList((Widget)ocw, ocw->ccontrol.textcallback,
+		       (XtPointer)arg);
+
+    ocw->onthespot.fixnotify = True;
+}
+
+/*- UpdateMode: update mode -*/
+static void
+UpdateMode(w)
+Widget w;
+{
+    OnTheSpotConversionWidget ocw = (OnTheSpotConversionWidget)w;
+    Widget inputobj = ocw->ccontrol.inputobj;
+    Atom encoding = ocw->ccontrol.textencoding;
+    int format;
+    int length;
+    XtPointer string;
+    int nchars;
+
+    TRACE(("OnTheSpotConversion:UpdateMode()\n"));
+
+    if (ICGetStatusString(inputobj, &encoding, &format, &length, &string,
+			  &nchars) == -1)
+	return;
+
+    CBStatusDraw(ocw, encoding, format, length, string, nchars);
+
+    /* string $B$r(B free $B$7$F$*$/(B */
+    XtFree((char *)string);
+}
+
+/*- SelectionControl: selection control -*/
+static void
+SelectionControl(w, arg)
+Widget w;
+ICSelectionControlArg *arg;
+{
+    OnTheSpotConversionWidget ocw = (OnTheSpotConversionWidget)w;
+    String params[1];
+    Cardinal num_params;
+
+    switch (arg->command) {
+    case ICSelectionStart:
+	SelectionStart(ocw, arg->u.selection_kind);
+	break;
+    case ICSelectionEnd:
+	SelectionEnd(ocw, &arg->u.current_item);
+	break;
+    case ICSelectionSet:
+	SelectionSet(ocw, arg->u.current_item);
+	break;
+    case ICSelectionMove:
+	SelectionMove(ocw, arg->u.dir);
+	break;
+    case ICSelectionGet:
+	SelectionGet(ocw, &arg->u.current_item);
+	break;
+    default:
+	params[0] = XtClass(w)->core_class.class_name;
+	num_params = 1;
+	XtAppWarningMsg(XtWidgetToApplicationContext(w),
+			"parameterError", "SelectionControl", "WidgetError",
+			"%s: unknown selection control command",
+			params, &num_params);
+	break;
+    }
+}
+
+/*- SelectionStart: selection startup -*/
+/* ARGSUSED */
+static void
+SelectionStart(ocw, kind)
+OnTheSpotConversionWidget ocw;
+int kind;
+{
+    Cardinal ncand;
+
+    TRACE(("OnTheSpotConversion:SelectionStart()\n"));
+    if (ocw->onthespot.selectionpoppedup) {
+	TRACE(("\tselection already started -- ignored\n"));
+	return;
+    }
+
+    ocw->onthespot.candlist = ICGetItemList(ocw->ccontrol.inputobj, &ncand);
+    ocw->onthespot.numcands = ncand;
+
+    TRACE(("\tnumcands=%d\n", ocw->onthespot.numcands));
+    CPanelSetList(ocw->onthespot.selectionwidget,
+		  ocw->onthespot.candlist,
+		  ocw->onthespot.numcands, 0, True);
+
+    LocateSelectionPopup(ocw);
+    XtPopup(ocw->onthespot.selectionshell, XtGrabNone);
+    ocw->onthespot.selectionpoppedup = True;
+}
+
+/*- LocateSelectionPopup: put selection popup at an appropriate position -*/
+static void
+LocateSelectionPopup(ocw)
+OnTheSpotConversionWidget ocw;
+{
+    Position x, y;
+    int clx, cly;
+    Dimension dpyWidth, dpyHeight;
+    Widget panel = ocw->onthespot.selectionwidget;
+    Widget shell = ocw->onthespot.selectionshell;
+    Window junk;
+    int barheight = ocw->ccontrol.titlebarheight;
+
+    (void)XTranslateCoordinates(XtDisplay(ocw),
+				ocw->ccontrol.clientwindow,
+				RootWindowOfScreen(XtScreen(ocw)),
+				0, 0, &clx, &cly, &junk);
+
+    (void)SafeGetWindowAttributes(XtDisplay(ocw), ocw->ccontrol.clientwindow,
+				  &(ocw->ccontrol.client_attr));
+
+    x = clx;
+    y = cly + ocw->ccontrol.client_attr.height;
+
+    dpyWidth = WidthOfScreen(XtScreen(shell));
+    dpyHeight = HeightOfScreen(XtScreen(shell));
+
+    if (x + panel->core.width > (int)dpyWidth) x = dpyWidth - panel->core.width;
+    if (x < 0) x = 0;
+#if 0
+    if (y + panel->core.height + barheight > (int)dpyHeight) {
+	y = cly - panel->core.height - 8 - barheight - 20; /* XXX */
+	if (y < 0) y = dpyHeight - panel->core.height - barheight;
+    }
+#endif
+    if (y + panel->core.height + barheight > (int)dpyHeight)
+	y = dpyHeight - panel->core.height - 8 - barheight - 20; /* XXX */
+    if (y < 0) y = 0;
+    MoveShell(shell, x, y);
+}
+
+/*- SelectionEnd: selection finish -*/
+static void
+SelectionEnd(ocw, current)
+OnTheSpotConversionWidget ocw;
+int *current;
+{
+    TRACE(("OnTheSpotConversion:SelectionEnd()\n"));
+
+    if (!ocw->onthespot.selectionpoppedup) {	/* for safe */
+	TRACE(("\tnot in selection mode -- ignored\n"));
+	return;
+    }
+
+    XtVaGetValues(ocw->onthespot.selectionwidget,
+		  XtNcurrentItem, current,
+		  NULL);
+
+    XtPopdown(ocw->onthespot.selectionshell);
+
+    ocw->onthespot.selectionpoppedup = False;
+}
+
+/*- SelectionSet: set current selection item -*/
+static void
+SelectionSet(ocw, current)
+OnTheSpotConversionWidget ocw;
+int current;
+{
+    TRACE(("OnTheSpotConversion:SelectionSet()\n"));
+
+    if (!ocw->onthespot.selectionpoppedup) {	/* for safe */
+	TRACE(("\tnot in selection mode -- ignored\n"));
+	return;
+    }
+
+    XtVaSetValues(ocw->onthespot.selectionwidget,
+		  XtNcurrentItem, current,
+		  NULL);
+}
+
+/*- SelectionGet: get current selection item -*/
+static void
+SelectionGet(ocw, current)
+OnTheSpotConversionWidget ocw;
+int *current;
+{
+    TRACE(("OnTheSpotConversion:SelectionGet()\n"));
+
+    if (!ocw->onthespot.selectionpoppedup) {	/* for safe */
+	TRACE(("\tnot in selection mode -- ignored\n"));
+	return;
+    }
+
+    XtVaGetValues(ocw->onthespot.selectionwidget,
+		  XtNcurrentItem, current,
+		  NULL);
+}
+
+/*- SelectionMove: move crrent selection to specified direction -*/
+static void
+SelectionMove(ocw, dir)
+OnTheSpotConversionWidget ocw;
+int dir;
+{
+    TRACE(("OnTheSpotConversion:SelectionMove()\n"));
+
+    if (!ocw->onthespot.selectionpoppedup) {	/* for safe */
+	TRACE(("\tnot in selection mode -- ignored\n"));
+	return;
+    }
+
+    CPanelMoveCurrent(ocw->onthespot.selectionwidget, dir);
+}
+
+/*
+ * Aux Callback
+ */
+
+static void
+AuxControl(w, arg)
+Widget w;
+ICAuxControlArg *arg;
+{
+    OnTheSpotConversionWidget ocw = (OnTheSpotConversionWidget)w;
+    String params[1];
+    Cardinal num_params;
+
+    switch (arg->command) {
+    case ICAuxStart:
+	AuxStart(ocw);
+	break;
+    case ICAuxEnd:
+	AuxEnd(ocw);
+	break;
+    case ICAuxChange:
+	AuxChange(ocw);
+	break;
+    default:
+	params[0] = XtClass(w)->core_class.class_name;
+	num_params = 1;
+	XtAppWarningMsg(XtWidgetToApplicationContext(w),
+			"parameterError", "AuxControl", "WidgetError",
+			"%s: unknown aux control command",
+			params, &num_params);
+	break;
+    }
+}
+
+/* ARGSUSED */
+static void
+AuxStart(ocw)
+OnTheSpotConversionWidget ocw;
+{
+  ICString *auxstr;
+  Cardinal ncand, curseg, cursorpos;
+  
+  if (ocw->onthespot.auxpoppedup) return;
+  
+  /* $B%F%-%9%H%3!<%k%P%C%/$N;~$N$h$&$J=hM}$r$9$k(B
+     $B$N$O(B AuxPanel.c $B$K$^$+$;$h$&(B */
+
+  auxstr = ICGetAuxSegments(ocw->ccontrol.inputobj,
+			    &ncand, &curseg, &cursorpos);
+
+  APanelStart(ocw->onthespot.auxwidget, auxstr, ncand, curseg, cursorpos);
+
+  /* $B%]%C%W%"%C%W$9$k>l=j$r7h$a$k(B */
+  LocateAuxPopup(ocw);
+
+  XtPopup(ocw->onthespot.auxshell, XtGrabNone);
+  ocw->onthespot.auxpoppedup = True;
+}
+
+/* ARGSUSED */
+static void
+AuxEnd(ocw)
+OnTheSpotConversionWidget ocw;
+{
+  if (!ocw->onthespot.auxpoppedup) return;	/* for safe */
+
+/*  APanelEnd(ocw->onthespot.auxwidget); */
+
+  XtPopdown(ocw->onthespot.auxshell);
+
+  ocw->onthespot.auxpoppedup = False;
+}
+
+/* ARGSUSED */
+static void
+AuxChange(ocw)
+OnTheSpotConversionWidget ocw;
+{
+  Cardinal ncand, curseg, cursorpos;
+  ICString *auxstr;
+
+  if (!ocw->onthespot.auxpoppedup) return;	/* for safe */
+
+  auxstr = ICGetAuxSegments(ocw->ccontrol.inputobj,
+			    &ncand, &curseg, &cursorpos);
+
+  APanelChange(ocw->onthespot.auxwidget, auxstr, ncand, curseg, cursorpos);
+}
+
+/*- LocateAuxPopup: put aux popup at an appropriate position -*/
+static void
+LocateAuxPopup(ocw)
+OnTheSpotConversionWidget ocw;
+{
+    Position x, y;
+    int clx, cly;
+    Dimension dpyWidth, dpyHeight;
+    Widget panel = ocw->onthespot.auxwidget;
+    Widget shell = ocw->onthespot.auxshell;
+    Window junk;
+    int barheight = ocw->ccontrol.titlebarheight;
+
+    (void)XTranslateCoordinates(XtDisplay(ocw),
+				ocw->ccontrol.clientwindow,
+				RootWindowOfScreen(XtScreen(ocw)),
+				0, 0, &clx, &cly, &junk);
+
+    (void)SafeGetWindowAttributes(XtDisplay(ocw), ocw->ccontrol.clientwindow,
+				  &(ocw->ccontrol.client_attr));
+
+    x = clx;
+    y = cly + ocw->ccontrol.client_attr.height;
+
+    dpyWidth = WidthOfScreen(XtScreen(shell));
+    dpyHeight = HeightOfScreen(XtScreen(shell));
+
+    if (x + panel->core.width > (int)dpyWidth) x = dpyWidth - panel->core.width;
+    if (x < 0) x = 0;
+#if 0
+    if (y + panel->core.height + barheight > (int)dpyHeight) {
+	y = cly - panel->core.height - 8 - barheight - 20; /* XXX */
+	if (y < 0) y = dpyHeight - panel->core.height - barheight;
+    }
+#endif
+    if (y + panel->core.height + barheight > (int)dpyHeight)
+	y = dpyHeight - panel->core.height - 8 - barheight - 20; /* XXX */
+    if (y < 0) y = 0;
+    MoveShell(shell, x, y);
+}
+
+/*
+ *+ Selection Widget callback
+ */
+
+/*- SelectionSelected: selection selected callback -*/
+/* ARGSUSED */
+static void
+SelectionSelected(w, client_data, call_data)
+Widget w;
+XtPointer client_data;
+XtPointer call_data;
+{
+    OnTheSpotConversionWidget ocw = (OnTheSpotConversionWidget)client_data;
+    int current = (int)call_data;
+
+    TRACE(("OnTheSpotConversion:SelectionSelected()\n"));
+    XtPopdown(ocw->onthespot.selectionshell);
+    ocw->onthespot.selectionpoppedup = False;
+    ICSelectItem(ocw->ccontrol.inputobj, current);
+}
+
+/*
+ *+ miscelaneous functions
+ */
+
+/*- SafeGetWindowAttributes: get window attributes -*/
+static Boolean
+SafeGetWindowAttributes(dpy, w, attr)
+Display *dpy;
+Window w;
+XWindowAttributes *attr;
+{
+    XAEHandle h;
+    unsigned long errbits = 0;
+
+    h = XAESetRecordErrors(dpy, &errbits);
+    (void)XGetWindowAttributes(dpy, w, attr);
+    XAEUnset(h);
+
+    return (errbits == 0);
+}
+
+/*- MoveShell: move shell widget -*/
+static void
+MoveShell(w, x, y)
+Widget w;
+Position x;
+Position y;
+{
+    XtWidgetGeometry req;
+
+    /*
+     * calling XtMoveWidget() is NOT enough to move shell widgets.
+     * we must use XtMakeGeometryRequest() or XtSetValues() to
+     * invoke root-geometry-manager which modifies the size hint
+     * appropriately.
+     */
+    req.request_mode = CWX | CWY;
+    req.x = x;
+    req.y = y;
+    (void)XtMakeGeometryRequest(w, &req, (XtWidgetGeometry *)NULL);
+}
+
+/*- getToplevelWindow: get top-level window of a given window -*/
+static Window
+getToplevelWindow(dpy, win)
+Display *dpy;
+Window win;
+{
+    Atom wm_state;
+    Atom type;
+    int format;
+    unsigned long nitems, bytesafter;
+    unsigned char *data;
+    Window root, parent;
+    Window *children;
+    unsigned int nchildren;
+
+    /*
+     * find toplevel window which has WM_STATE property or if no exists,
+     * direct subwindow of the root window. (ie I assume that if a
+     * window manager is running, that is a ICCCM compliant one)
+     */
+    wm_state = CachedInternAtom(dpy, "WM_STATE", True);
+    for (;;) {
+	type = None;
+	if (wm_state != None) {
+	    data = NULL;
+	    XGetWindowProperty(dpy, win, wm_state, 0L, 0L, False,
+			       AnyPropertyType, &type, &format,
+			       &nitems, &bytesafter, &data);
+	    if (data != NULL) XtFree((char *)data);
+	    if (type != None) break;
+	}
+	if (!XQueryTree(dpy, win, &root, &parent, &children, &nchildren)) break;
+	if (nchildren > 0) XtFree((char *)children);
+	if (root == parent) break;
+	win = parent;
+    }
+    return win;
+}
+
+/*- setTransientFor: set WM_TRANSIENT_FOR property to specified widget -*/
+static void
+setTransientFor(w, win)
+Widget w;
+Window win;
+{
+    if (!XtIsRealized(w)) XtRealizeWidget(w);
+    XSetTransientForHint(XtDisplay(w), XtWindow(w), win);
+}
+
+/*- allocDisplaySegments: prepare specified number of display segments -*/
+static void
+allocDisplaySegments(ocw, n)
+OnTheSpotConversionWidget ocw;
+Cardinal n;
+{
+    if (ocw->onthespot.dispsegmentsize > n) return;
+    n = ((n + 3) / 4) * 4 ;
+    if (ocw->onthespot.dispsegments == NULL) {
+	ocw->onthespot.dispsegments = (DisplaySegment *)XtMalloc(n * sizeof(DisplaySegment));
+    } else {
+	ocw->onthespot.dispsegments = (DisplaySegment *)XtRealloc((char *)ocw->onthespot.dispsegments, n * sizeof(DisplaySegment));
+    }
+    ocw->onthespot.dispsegmentsize = n;
+}
+
+/*- freeDisplaySegment: free display segment's contents -*/
+static void
+freeDisplaySegment(dsp)
+DisplaySegment *dsp;
+{
+    freeString(&dsp->seg);
+}
+
+/*- clearAllDisplaySegments: clear all display segment's -*/
+static void
+clearAllDisplaySegments(ocw)
+OnTheSpotConversionWidget ocw;
+{
+    DisplaySegment *dsp = ocw->onthespot.dispsegments;
+    int i;
+
+    for (i = 0; i < ocw->onthespot.numsegments; i++) {
+	freeDisplaySegment(dsp++);
+    }
+    ocw->onthespot.numsegments = 0;
+}
+
+/*- copyString: copy ICString -*/
+static void
+copyString(from, to)
+ICString *from;
+ICString *to;
+{
+    *to = *from;
+    to->data = XtMalloc(to->nbytes);
+    (void)bcopy(from->data, to->data, to->nbytes);
+}
+
+/*- freeString: free ICString -*/
+static void
+freeString(seg)
+ICString *seg;
+{
+    XtFree(seg->data);
+    seg->data = NULL;
+    seg->nbytes = 0;
+}
+
+/*- allocAttributeBuffer: allocate attribute buffer -*/
+static AttributeBuffer *
+allocAttributeBuffer()
+{
+    AttributeBuffer *buffer;
+
+    buffer = (AttributeBuffer *)XtMalloc(sizeof(AttributeBuffer));
+    buffer->attrs_length = 0;
+    buffer->attrs_limit = 64;
+    buffer->attrs_buffer = (unsigned long *)XtMalloc(buffer->attrs_limit * sizeof(unsigned long));
+    return buffer;
+}
+
+/*- destroyAttributeBuffer: destroy draw string buffer's contents -*/
+static void
+destroyAttributeBuffer(buffer)
+AttributeBuffer *buffer;
+{
+    XtFree((char *)buffer->attrs_buffer);
+    XtFree((char *)buffer);
+}
+
+/*- addAttributeBuffer: add segment to draw string buffer's contents -*/
+static void
+addAttributeBuffer(buffer, inputobj, seg, offset, fba)
+AttributeBuffer *buffer;
+Widget inputobj;
+ICString *seg;
+int offset;
+FeedbackAttributes *fba;
+{
+    int nchars = seg->nchars - offset;
+    unsigned long fb;
+    int i;
+
+    if (buffer->attrs_length + nchars > buffer->attrs_limit) {
+	unsigned long *new_attrs_buffer;
+	int new_limit = buffer->attrs_limit * 2;
+	if (new_limit < buffer->attrs_length + nchars)
+	    new_limit = buffer->attrs_length + nchars + 8;
+	new_attrs_buffer = (unsigned long *)XtMalloc(new_limit * sizeof(unsigned long));
+	bcopy(buffer->attrs_buffer, new_attrs_buffer,
+	      buffer->attrs_length * sizeof(unsigned long));
+	XtFree((char *)buffer->attrs_buffer);
+	buffer->attrs_limit = new_limit;
+	buffer->attrs_buffer = new_attrs_buffer;
+    }
+    fb = attrToFeedback(fba, seg->attr);
+    for (i = 0; i < nchars; i++) {
+	buffer->attrs_buffer[buffer->attrs_length + i] = fb;
+    }
+    buffer->attrs_length += nchars;
+}
+
+/*- attrToFeedback: ICString attribute -> XIMFeedback attribute converter -*/
+static unsigned long
+attrToFeedback(fba, attr)
+FeedbackAttributes *fba;
+int attr;
+{
+    int idx;
+
+    if (attr == ICAttrNormalString) return 0;
+
+    if (!(attr & ICAttrConverted)) {
+	/* Not yet converted */
+	idx = FEEDBACK_NOCONV;
+    } else if (attr & ICAttrCurrentSegment) {
+	/* it's converted and the current segment */
+	idx = FEEDBACK_CURRENT;
+    } else if (attr & ICAttrCurrentSubSegment) {
+	/* it's converted and the current sub segment */
+	idx = FEEDBACK_CURRENTSUB;
+    } else {
+	/* converted, not current */
+	idx = FEEDBACK_CONV;
+    }
+    return fba->feedbacks[idx];
+}
+
+/*- CBPreeditStart: callback preedit start -*/
+static void
+CBPreeditStart(ocw)
+OnTheSpotConversionWidget ocw;
+{
+    if (ocw->onthespot.preeditstartcallback == NULL ||
+	XtHasCallbacks((Widget)ocw, XtNpreeditStartCallback) != XtCallbackHasSome)
+    {
+	/* no callback */
+	return;
+    }
+
+    TRACE(("OnTheSpot:CBPreeditStart()\n"));
+
+    XtCallCallbackList((Widget)ocw, ocw->onthespot.preeditstartcallback,
+		       (XtPointer)NULL);
+}
+
+/*- CBPreeditDone: callback preedit done -*/
+static void
+CBPreeditDone(ocw)
+OnTheSpotConversionWidget ocw;
+{
+    if (ocw->onthespot.preeditdonecallback == NULL ||
+	XtHasCallbacks((Widget)ocw, XtNpreeditDoneCallback) != XtCallbackHasSome)
+    {
+	/* no callback */
+	return;
+    }
+
+    TRACE(("OnTheSpot:CBPreeditDone()\n"));
+
+    XtCallCallbackList((Widget)ocw, ocw->onthespot.preeditdonecallback,
+		       (XtPointer)NULL);
+}
+
+/*- CBPreeditDraw: callback preedit draw -*/
+static void
+CBPreeditDraw(ocw, caret, chg_first, chg_length, encoding, format, text_length, text, attrs_length, attrs)
+OnTheSpotConversionWidget ocw;
+int caret;
+int chg_first;
+int chg_length;
+Atom encoding;
+int format;
+int text_length;
+XtPointer text;
+int attrs_length;
+unsigned long *attrs;
+{
+    OCCPreeditDrawArg arg;
+
+    if (ocw->onthespot.preeditdrawcallback == NULL ||
+	XtHasCallbacks((Widget)ocw, XtNpreeditDrawCallback) != XtCallbackHasSome)
+    {
+	/* no callback */
+	return;
+    }
+
+    TRACE(("OnTheSpot:CBPreeditDraw()\n"));
+
+    arg.caret = caret;
+    arg.chg_first = chg_first;
+    arg.chg_length = chg_length;
+    arg.encoding = encoding;
+    arg.format = format;
+    arg.text_length = text_length;
+    arg.text = text;
+    arg.attrs_length = attrs_length;
+    arg.attrs = attrs;
+    XtCallCallbackList((Widget)ocw, ocw->onthespot.preeditdrawcallback,
+		       (XtPointer)&arg);
+}
+
+/*- CBPreeditCaret: callback preedit caret -*/
+static void
+CBPreeditCaret(ocw, caret)
+OnTheSpotConversionWidget ocw;
+int caret;
+{
+    if (ocw->onthespot.preeditcaretcallback == NULL ||
+	XtHasCallbacks((Widget)ocw, XtNpreeditCaretCallback) != XtCallbackHasSome)
+    {
+	/* no callback */
+	return;
+    }
+
+    TRACE(("OnTheSpot:CBPreeditCaret()\n"));
+
+    XtCallCallbackList((Widget)ocw, ocw->onthespot.preeditcaretcallback,
+		       (XtPointer)caret);
+}
+
+/*- CBStatusStart: callback status start -*/
+static void
+CBStatusStart(ocw)
+OnTheSpotConversionWidget ocw;
+{
+    if (ocw->onthespot.statusstartcallback == NULL ||
+	XtHasCallbacks((Widget)ocw, XtNstatusStartCallback) != XtCallbackHasSome)
+    {
+	/* no callback */
+	return;
+    }
+
+    TRACE(("OnTheSpot:CBStatusStart()\n"));
+
+    XtCallCallbackList((Widget)ocw, ocw->onthespot.statusstartcallback,
+		       (XtPointer)NULL);
+}
+
+/*- CBStatusDone: callback status done -*/
+static void
+CBStatusDone(ocw)
+OnTheSpotConversionWidget ocw;
+{
+    if (ocw->onthespot.statusdonecallback == NULL ||
+	XtHasCallbacks((Widget)ocw, XtNstatusDoneCallback) != XtCallbackHasSome)
+    {
+	/* no callback */
+	return;
+    }
+
+    TRACE(("OnTheSpot:CBStatusDone()\n"));
+
+    XtCallCallbackList((Widget)ocw, ocw->onthespot.statusdonecallback,
+		       (XtPointer)NULL);
+}
+
+/*- CBStatusDraw: callback status draw -*/
+static void
+CBStatusDraw(ocw, encoding, format, length, text, nchars)
+OnTheSpotConversionWidget ocw;
+Atom encoding;
+int format;
+int length;
+XtPointer text;
+int nchars;
+{
+    OCCPreeditDrawArg arg;
+
+    if (ocw->onthespot.statusdrawcallback == NULL ||
+	XtHasCallbacks((Widget)ocw, XtNstatusDrawCallback) != XtCallbackHasSome)
+    {
+	/* no callback */
+	return;
+    }
+
+    TRACE(("OnTheSpot:CBStatusDraw()\n"));
+
+    arg.caret = 0;	/* ignored */
+    arg.chg_first = 0;	/* ignored */
+    arg.chg_length = 0;	/* ignored */
+    arg.encoding = encoding;
+    arg.format = format;
+    arg.text_length = length;
+    arg.text = text;
+    arg.attrs_length = nchars;
+    arg.attrs = NULL;	/* ignored */
+    XtCallCallbackList((Widget)ocw, ocw->onthespot.statusdrawcallback,
+		       (XtPointer)&arg);
+}
+