diff lib/OffConv.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/OffConv.c	Mon Mar 08 04:44:30 2010 +0900
@@ -0,0 +1,2045 @@
+#ifndef lint
+static char *rcsid = "$Id: OffConv.c,v 1.44 2001/07/01 13:47:00 ishisone Exp $";
+#endif
+/*
+ * 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
+ */
+
+/*
+ * Note: This file contains TWO widget classes, OffTheSpotConversionWidget
+ *       and its subclass SeparateConversionWidget.
+ */
+
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+#if XtSpecificationRelease > 4
+#include <X11/Xfuncs.h>
+#endif
+#include "CachedAtom.h"
+#include "AsyncErr.h"
+#include "OffConvP.h"
+#include <X11/Xaw/Form.h>
+#include "InputConv.h"
+#include "ConvDisp.h"
+#include "CandPanel.h"
+#include "AuxPanel.h"
+#include "Canvas.h"
+#include "AdoptedShe.h"
+#include "CanvasShel.h"
+#include "ICLabel.h"
+
+#define DEBUG_VAR debug_OffTheSpotConversion
+#include "DebugPrint.h"
+
+/*- resource table for OffTheSpotConversion (SeparateConversion has no resources -*/
+static XtResource off_resources[] = {
+#define offset(field) XtOffset(OffTheSpotConversionWidget, offthespot.field)
+    { XtNleftMargin, XtCMargin, XtRDimension, sizeof(Dimension),
+	offset(leftmargin), XtRImmediate, (XtPointer)2 },
+    { XtNrightMargin, XtCMargin, XtRDimension, sizeof(Dimension),
+	offset(rightmargin), XtRImmediate, (XtPointer)2 },
+#undef offset
+};
+
+/*- default translations -- same as superclass's -*/
+static char off_translations[] = "<Key>: to-inputobj()";
+static char sep_translations[] = "<Key>: to-inputobj()";
+
+/*- declarations of static functions -*/
+static void OffTheSpot_Initialize();
+static void OffTheSpot_Destroy();
+static Boolean OffTheSpot_SetValues();
+static void OffTheSpot_Startup();
+static void OffTheSpot_ConversionFinish();
+static void OffTheSpot_ChangeAttributes();
+static void OffTheSpot_ChangeFocus();
+
+static void Separate_Initialize();
+static void Separate_Startup();
+static void Separate_ConversionFinish();
+static void Separate_ChangeAttributes();
+static void Separate_ChangeFocus();
+
+static Widget CreateDisplayObject();
+static Widget CreateSelectionWidget();
+
+static void SetupDisplayObject();
+static Boolean ResetDisplayObject();
+static void SetupModeWidget();
+static Boolean ResetModeWidget();
+static void SetupCanvasWidget();
+static Boolean ResetCanvasWidget();
+
+static void UpdateText();
+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 TextRedisplay();
+static void TextResize();
+
+static void SelectionSelected();
+
+static void computeDisplaySegments();
+static void recomputeDisplaySegments();
+static void computeLastPosition();
+static DisplayFragment * computeDisplayFragments();
+static int widthAvailable();
+static void initialLocation();
+static void nextLocation();
+static DisplayLocation * findLocation();
+static void reconfigureDisplay();
+static void updateDisplay();
+static void updateDisplaySegment();
+static void redrawSegments();
+
+static void eraseCursor();
+static void showCursor();
+static Boolean exposeCursor();
+static void computeCursor();
+
+static void MoveShell();
+static Window getToplevelWindow();
+static void setTransientFor();
+static Boolean intersectRect();
+static void unionRect();
+static DisplayFragment * allocDisplayFragment();
+static void freeDisplayFragments();
+static void destroyDisplayFragments();
+static void allocDisplaySegments();
+static void freeDisplaySegment();
+static void clearAllDisplaySegments();
+static void copyString();
+static void freeString();
+
+/*- 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,
+};
+
+/*- offTheSpotConversionClass record -*/
+OffTheSpotConversionClassRec offTheSpotConversionClassRec = {
+  { /* core fields */
+    /* superclass		*/	(WidgetClass)&conversionControlClassRec,
+    /* class_name		*/	"OffTheSpotConversion",
+    /* widget_size		*/	sizeof(OffTheSpotConversionRec),
+    /* class_initialize		*/	NULL,
+    /* class_part_initialize	*/	NULL,
+    /* class_inited		*/	FALSE,
+    /* initialize		*/	OffTheSpot_Initialize,
+    /* initialize_hook		*/	NULL,
+    /* realize			*/	XtInheritRealize,
+    /* actions			*/	NULL,
+    /* num_actions		*/	0,
+    /* resources		*/	off_resources,
+    /* num_resources		*/	XtNumber(off_resources),
+    /* xrm_class		*/	NULLQUARK,
+    /* compress_motion		*/	TRUE,
+    /* compress_exposure	*/	TRUE,
+    /* compress_enterleave	*/	TRUE,
+    /* visible_interest		*/	FALSE,
+    /* destroy			*/	OffTheSpot_Destroy,
+    /* resize			*/	XtInheritResize,
+    /* expose			*/	NULL,
+    /* set_values		*/	OffTheSpot_SetValues,
+    /* set_values_hook		*/	NULL,
+    /* set_values_almost	*/	XtInheritSetValuesAlmost,
+    /* get_values_hook		*/	NULL,
+    /* accept_focus		*/	NULL,
+    /* version			*/	XtVersion,
+    /* callback_private		*/	NULL,
+    /* tm_table			*/	off_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			*/	OffTheSpot_Startup,
+    /* Finish			*/	OffTheSpot_ConversionFinish,
+    /* ChangeAttributes		*/	OffTheSpot_ChangeAttributes,
+    /* ChangeFocus		*/	OffTheSpot_ChangeFocus,
+    /* TextChange		*/	UpdateText,
+    /* Fix			*/	XtInheritFix,
+    /* ModeChange		*/	UpdateMode,
+    /* SelectionControl		*/	SelectionControl,
+    /* AuxControl		*/	AuxControl,
+  },
+  { /* offTheSpotConversion fields */
+    /* empty			*/	0
+  },
+};
+
+WidgetClass offTheSpotConversionWidgetClass = (WidgetClass)&offTheSpotConversionClassRec;
+
+/*- separateConversionClass record -*/
+SeparateConversionClassRec separateConversionClassRec = {
+  { /* core fields */
+    /* superclass		*/	(WidgetClass)&offTheSpotConversionClassRec,
+    /* class_name		*/	"SeparateConversion",
+    /* widget_size		*/	sizeof(SeparateConversionRec),
+    /* class_initialize		*/	NULL,
+    /* class_part_initialize	*/	NULL,
+    /* class_inited		*/	FALSE,
+    /* initialize		*/	Separate_Initialize,
+    /* initialize_hook		*/	NULL,
+    /* realize			*/	XtInheritRealize,
+    /* actions			*/	NULL,
+    /* num_actions		*/	0,
+    /* resources		*/	NULL,
+    /* num_resources		*/	0,
+    /* xrm_class		*/	NULLQUARK,
+    /* compress_motion		*/	TRUE,
+    /* compress_exposure	*/	TRUE,
+    /* compress_enterleave	*/	TRUE,
+    /* visible_interest		*/	FALSE,
+    /* destroy			*/	NULL,
+    /* resize			*/	XtInheritResize,
+    /* expose			*/	NULL,
+    /* set_values		*/	NULL,
+    /* set_values_hook		*/	NULL,
+    /* set_values_almost	*/	XtInheritSetValuesAlmost,
+    /* get_values_hook		*/	NULL,
+    /* accept_focus		*/	NULL,
+    /* version			*/	XtVersion,
+    /* callback_private		*/	NULL,
+    /* tm_table			*/	sep_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			*/	Separate_Startup,
+    /* Finish			*/	Separate_ConversionFinish,
+    /* ChangeAttributes		*/	Separate_ChangeAttributes,
+    /* ChangeFocus		*/	Separate_ChangeFocus,
+    /* TextChange		*/	XtInheritTextChange,
+    /* Fix			*/	XtInheritFix,
+    /* ModeChange		*/	XtInheritModeChange,
+    /* SelectionControl		*/	XtInheritSelectionControl,
+    /* AuxControl		*/	XtInheritAuxControl,
+  },
+  { /* offTheSpotConversion fields */
+    /* empty			*/	0
+  },
+  { /* separateConversion fields */
+    /* empty			*/	0
+  },
+};
+
+WidgetClass separateConversionWidgetClass = (WidgetClass)&separateConversionClassRec;
+
+/*
+ *+ OffTheSpot -- Core class method
+ */
+
+/*- OffTheSpot_Initialize: initalize method for OffTheSpotCoversion -*/
+/* ARGSUSED */
+static void
+OffTheSpot_Initialize(req, new, args, num_args)
+Widget req;
+Widget new;
+ArgList args;
+Cardinal *num_args;
+{
+    OffTheSpotConversionWidget ocw = (OffTheSpotConversionWidget)new;
+
+    (void)CreateDisplayObject(ocw);
+    (void)CreateSelectionWidget(ocw);
+    (void)CreateAuxWidget(ocw);
+
+    ocw->offthespot.canvaswidget = NULL;
+    ocw->offthespot.modewidget = NULL;
+    ocw->offthespot.modeshell = NULL;
+
+    ocw->offthespot.dispsegments = NULL;
+    ocw->offthespot.numsegments = 0;
+    ocw->offthespot.dispsegmentsize = 0;
+    ocw->offthespot.candlist = NULL;
+    ocw->offthespot.numcands = 0;
+    ocw->offthespot.selectionpoppedup = False;
+    ocw->offthespot.auxpoppedup = False;
+}
+
+/*- OffTheSpot_Destroy: destroy method for OffTheSpotCoversion -*/
+static void
+OffTheSpot_Destroy(w)
+Widget w;
+{
+    OffTheSpotConversionWidget ocw = (OffTheSpotConversionWidget)w;
+
+    /* $B%G%#%9%W%l%$%;%0%a%s%H$NNN0h$r2rJ|(B */
+    if (ocw->offthespot.dispsegments) {
+	DisplaySegment *dsp = ocw->offthespot.dispsegments;
+	int i;
+
+	for (i = 0; i < ocw->offthespot.numsegments; i++) {
+	    freeString(&dsp[i].seg);
+	    destroyDisplayFragments(dsp->fragments);
+	}
+	XtFree((char *)dsp);
+    }
+}
+
+/*- OffTheSpot_SetValues: setvalues method for OffTheSpotCoversion -*/
+/* ARGSUSED */
+static Boolean
+OffTheSpot_SetValues(cur, req, new, args, num_args)
+Widget cur;
+Widget req;
+Widget new;
+ArgList args;
+Cardinal *num_args;
+{
+    /* OffTheSpotConversionWidget ocw = (OffTheSpotConversionWidget)new; */
+    return False;
+}
+
+/*
+ *+ OffTheSpot -- ConversionControl class method
+ */
+
+/*- OffTheSpot_Startup: OffTheSpot conversion startup -*/
+static void
+OffTheSpot_Startup(widget, valuemask, value)
+Widget widget;
+unsigned long valuemask;
+ConversionAttributes *value;
+{
+    OffTheSpotConversionWidget ocw = (OffTheSpotConversionWidget)widget;
+    Window toplevel;
+
+    if (!(valuemask & CAStatusArea)) {
+	String params[1];
+	Cardinal num_params = 1;
+
+	params[0] = XtClass(widget)->core_class.class_name;
+	XtAppErrorMsg(XtWidgetToApplicationContext(widget),
+		      "conversionAttributeError", "statusArea", "WidgetError",
+		      "%s: status area must be specified",
+		      params, &num_params);
+    }
+
+    SetupDisplayObject(ocw, valuemask, value);
+    SetupModeWidget(ocw, valuemask, value);
+    SetupCanvasWidget(ocw, valuemask, value);
+
+    /* $BFbIt$N%P%C%U%!$r%/%j%"$9$k(B */
+    clearAllDisplaySegments(ocw);
+
+    /* $B%+!<%=%k$N@_Dj(B */
+    ocw->offthespot.cursorvisible = True;
+    eraseCursor(ocw);
+    ocw->offthespot.cursorvisible = True;
+    initialLocation(ocw, &(ocw->offthespot.cursorlocation));
+    ocw->offthespot.cursorlocation.y += ocw->offthespot.ascent;
+
+    /* 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->offthespot.selectionshell, toplevel);
+    setTransientFor(ocw->offthespot.auxshell, toplevel);
+
+    /*
+     * OffTheSpotConvesion $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);
+    }
+
+    /* $B%]%C%W%"%C%W$9$k(B */
+    XtPopup(ocw->offthespot.modeshell, XtGrabNone);
+    XtPopup(ocw->offthespot.canvaswidget, XtGrabNone);
+}
+
+/*- OffTheSpot_ConversionFinish: OffTheSpot conversion finish -*/
+/* ARGSUSED */
+static void
+OffTheSpot_ConversionFinish(w)
+Widget w;
+{
+    OffTheSpotConversionWidget ocw = (OffTheSpotConversionWidget)w;
+    XAEHandle h;
+
+    /* Popdown and unrealize textcanvas and mode widget
+     *	we must be careful here. if clientwindow are destroyed,
+     *	the text canvas and mode widget are also destroyed.
+     *	we have to popdown and unrealize those widgets, but if
+     *	they are destroyed, BadWindow error will be generated.
+     *	so we must set own error handler that ignores errors.
+     */
+    h = XAESetIgnoreErrors(XtDisplay(w));
+    XtPopdown(ocw->offthespot.modeshell);
+    XtUnrealizeWidget(ocw->offthespot.modeshell);
+    XtPopdown(ocw->offthespot.canvaswidget);
+    XtUnrealizeWidget(ocw->offthespot.canvaswidget);
+    XAEUnset(h);
+
+    if (ocw->offthespot.selectionpoppedup) {
+	XtPopdown(ocw->offthespot.selectionshell);
+	ocw->offthespot.selectionpoppedup = False;
+    }
+    if (ocw->offthespot.auxpoppedup) {
+	XtPopdown(ocw->offthespot.auxshell);
+	ocw->offthespot.auxpoppedup = False;
+    }
+}
+
+/*- OffTheSpot_ChangeAttributes: OffTheSpot conversion attribute change -*/
+/* ARGSUSED */
+static void
+OffTheSpot_ChangeAttributes(w, valuemask, value)
+Widget w;
+unsigned long valuemask;
+ConversionAttributes *value;
+{
+    OffTheSpotConversionWidget ocw = (OffTheSpotConversionWidget)w;
+    Boolean redraw, reconfig;
+
+    if (ResetModeWidget(ocw, valuemask, value) &&
+	XtIsRealized(ocw->offthespot.modewidget)) {
+	XClearArea(XtDisplay(w), XtWindow((Widget)ocw->offthespot.modewidget),
+		   0, 0, 0, 0, True);
+    }
+
+    redraw = ResetDisplayObject(ocw, valuemask, value);
+    reconfig = ResetCanvasWidget(ocw, valuemask, value);
+
+    if (reconfig) {
+	TextResize(ocw->offthespot.canvaswidget, (XtPointer)w, (XtPointer)NULL);
+    } else if (redraw && XtIsRealized(ocw->offthespot.canvaswidget)) {
+	XClearArea(XtDisplay(w), XtWindow(ocw->offthespot.canvaswidget),
+		   0, 0, 0, 0, True);
+    }
+}
+
+/*- OffTheSpot_ChangeFocus: OffTheSpot focus change -*/
+static void
+OffTheSpot_ChangeFocus(w, set)
+Widget w;
+int set;
+{
+    OffTheSpotConversionWidget ocw = (OffTheSpotConversionWidget)w;
+
+    if (set) {
+	XtPopup(ocw->offthespot.modeshell, XtGrabNone);
+	XtPopup(ocw->offthespot.canvaswidget, XtGrabNone);
+    } else {
+	XtPopdown(ocw->offthespot.modeshell);
+	XtPopdown(ocw->offthespot.canvaswidget);
+    }
+}
+
+/*
+ *+ Separate -- Core class method
+ */
+
+/*- Separate_Initialize: initialize method for SeparateConversion -*/
+/* ARGSUSED */
+static void
+Separate_Initialize(req, new, args, num_args)
+Widget req;
+Widget new;
+ArgList args;
+Cardinal *num_args;
+{
+    SeparateConversionWidget scw = (SeparateConversionWidget)new;
+    Widget inputobj = scw->ccontrol.inputobj;
+    Widget form, canvas, mode, tmp[2];
+
+    form = XtCreateManagedWidget("form", formWidgetClass, (Widget)scw,
+				 NULL, 0);
+    tmp[0] = mode = XtVaCreateWidget("mode", icLabelWidgetClass, form,
+				     XtNlabel, ICGetMode(inputobj),
+				     NULL);
+    (void)XtCreateWidget("display", scw->ccontrol.displayobjclass, mode,
+			 NULL, 0);
+
+    tmp[1] = canvas = XtCreateWidget("text", canvasWidgetClass, form, NULL, 0);
+    XtManageChildren(tmp, 2);
+
+    XtAddCallback(canvas, XtNexposeCallback, TextRedisplay, (XtPointer)scw);
+    XtAddCallback(canvas, XtNresizeCallback, TextResize, (XtPointer)scw);
+
+    XtInstallAccelerators(canvas, (Widget)scw);
+    XtInstallAccelerators(mode, (Widget)scw);
+    XtInstallAccelerators(form, (Widget)scw);
+
+    scw->separate.formwidget = form;
+    scw->offthespot.canvaswidget = canvas;
+    scw->offthespot.modewidget = mode;
+
+}
+
+/*
+ *+ Separate -- ConversionControl class method
+ */
+
+/*- Separate_Startup: Separate conversion startup -*/
+/* ARGSUSED */
+static void
+Separate_Startup(widget, valuemask, value)
+Widget widget;
+unsigned long valuemask;
+ConversionAttributes *value;
+{
+    SeparateConversionWidget scw = (SeparateConversionWidget)widget;
+    Position clx, cly;
+    Dimension clw, clh;
+    Position x, y;
+    Dimension w, h;
+    Dimension dpyWidth, dpyHeight;
+    Window toplevel;
+
+    /* $BFbIt$N%P%C%U%!$r%/%j%"$9$k(B */
+    clearAllDisplaySegments((OffTheSpotConversionWidget)scw);
+
+    /* $B%+!<%=%k$N@_Dj(B */
+    scw->offthespot.cursorvisible = True;
+    eraseCursor((OffTheSpotConversionWidget)scw);
+    scw->offthespot.cursorvisible = True;
+    initialLocation((OffTheSpotConversionWidget)scw,
+		    &(scw->offthespot.cursorlocation));
+    scw->offthespot.cursorlocation.y += scw->offthespot.ascent;
+
+    /* $B=i4|%b!<%I$r@_Dj$9$k(B */
+    XtVaSetValues(scw->offthespot.modewidget,
+		  XtNlabel, ICGetMode(scw->ccontrol.inputobj),
+		  NULL);
+
+    /* $BI=<(0LCV$r7h$a$k(B */
+    clx = scw->ccontrol.client_rootx;
+    cly = scw->ccontrol.client_rooty;
+    clw = scw->ccontrol.client_attr.width;
+    clh = scw->ccontrol.client_attr.height;
+
+    XtRealizeWidget((Widget)scw);
+    w =  scw->core.width;
+    h =  scw->core.height;
+    DPRINT(("Off_the_spot_Startup(): widget size = %dx%d\n", w, h));
+    x =  clx + clw / 2 - w / 2;
+    y =  cly + clh + 8;
+
+    dpyWidth = WidthOfScreen(XtScreen(widget));
+    dpyHeight = HeightOfScreen(XtScreen(widget));
+
+    if (x + w > dpyWidth) x = dpyWidth - w;
+    if (x < 0) x = 0;
+    if (y + h > dpyHeight) {
+	y = cly - h;
+	if (y < 0) y = dpyHeight - h;
+    }
+    MoveShell(widget, x, y);
+
+    /* WM_TRANSIENT_FOR $B%W%m%Q%F%#$r@5$7$/%;%C%H$9$k(B */
+    toplevel = getToplevelWindow(XtDisplay(widget),
+				 scw->ccontrol.clientwindow);
+    setTransientFor((Widget)scw, toplevel);
+
+    /*
+     * This is a kind of a magic word... I don't know why, but without this
+     * the selection popup will appear in wrong size (1x1) at the first time.
+     */
+    XtRealizeWidget(scw->offthespot.selectionshell);
+    XtRealizeWidget(scw->offthespot.auxshell);
+
+    /* $B%]%C%W%"%C%W$9$k(B */
+    XtPopup(widget, XtGrabNone);
+}
+
+/*- Separate_ConversionFinish: Separate conversion finish -*/
+/* ARGSUSED */
+static void
+Separate_ConversionFinish(w)
+Widget w;
+{
+    SeparateConversionWidget scw = (SeparateConversionWidget)w;
+
+    if (scw->offthespot.selectionpoppedup) {
+	XtPopdown(scw->offthespot.selectionshell);
+	scw->offthespot.selectionpoppedup = False;
+    }
+    if (scw->offthespot.auxpoppedup) {
+	XtPopdown(scw->offthespot.auxshell);
+	scw->offthespot.auxpoppedup = False;
+    }
+    XtPopdown(w);
+}
+
+/*- Separate_ChangeAttributes: Separate conversion attribute change -*/
+/* ARGSUSED */
+static void
+Separate_ChangeAttributes(w, mask, value)
+Widget w;
+unsigned long mask;
+ConversionAttributes *value;
+{
+    /* do nothing */
+}
+
+/*- Separate_ChangeFocus: Separate focus change -*/
+/* ARGSUSED */
+static void
+Separate_ChangeFocus(w, set)
+Widget w;
+int set;
+{
+    /* do nothing */
+}
+
+/*
+ *+ sub-widget creation
+ */
+
+/*- CreateDisplayObject: create display object for text drawing -*/
+static Widget
+CreateDisplayObject(ocw)
+OffTheSpotConversionWidget ocw;
+{
+    Widget dispobj;
+
+    dispobj = XtCreateWidget("displayObj", ocw->ccontrol.displayobjclass,
+			     (Widget)ocw, NULL, 0);
+
+    ocw->offthespot.displayobj = dispobj;
+    ocw->offthespot.lineheight = CDLineHeight(dispobj, &ocw->offthespot.ascent);
+
+    return dispobj;
+}
+
+/*- CreateSelectionWidget: create selection widget for selecting candidates -*/
+static Widget
+CreateSelectionWidget(ocw)
+OffTheSpotConversionWidget 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->offthespot.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->offthespot.selectionwidget = sel;
+
+    return shell;
+}
+
+/*- CreateAuxWidget: create aux widget for display auxiliary data -*/
+static Widget
+CreateAuxWidget(ocw)
+OffTheSpotConversionWidget 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->offthespot.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->offthespot.auxwidget = sel;
+
+    return shell;
+}
+
+/*
+ *+ subwidget configuration
+ */
+
+/*- SetupDisplayObject: do display objetct configuration on conversion startup -*/
+static void
+SetupDisplayObject(ocw, mask, value)
+OffTheSpotConversionWidget ocw;
+unsigned long mask;
+ConversionAttributes *value;
+{
+    /*
+     * order is important. we must set fonts BEFORE anything else,
+     * because it is possible that the fonts previously set in the
+     * display object no longer exist, and if so, that causes BadFont
+     * error when changing GCs.
+     */
+
+    if (mask & CAFonts) {
+	CDSetFonts(ocw->offthespot.displayobj,
+		   value->fonts, value->num_fonts);
+    } else {
+	CDSetFonts(ocw->offthespot.displayobj, (XFontStruct **)NULL, 0);
+    }
+    if (mask & CAColor) {
+	XtVaSetValues(ocw->offthespot.displayobj,
+		      XtNforeground, value->foreground,
+		      XtNbackground, value->background,
+		      NULL);
+    }
+
+    ocw->offthespot.lineheight = CDLineHeight(ocw->offthespot.displayobj,
+					      &ocw->offthespot.ascent);
+}
+
+/*- ResetDisplayObject: do display objetct reconfiguration on attribute change -*/
+static Boolean
+ResetDisplayObject(ocw, mask, value)
+OffTheSpotConversionWidget ocw;
+unsigned long mask;
+ConversionAttributes *value;
+{
+    Boolean redraw = False;
+
+    if (mask & CAColor) {
+	XtVaSetValues(ocw->offthespot.displayobj,
+		      XtNforeground, value->foreground,
+		      XtNbackground, value->background,
+		      NULL);
+	redraw = True;
+    }
+    if (mask & CAFonts) {
+	CDSetFonts(ocw->offthespot.displayobj,
+		   value->fonts, value->num_fonts);
+	redraw = True;
+	ocw->offthespot.lineheight = CDLineHeight(ocw->offthespot.displayobj,
+						  &ocw->offthespot.ascent);
+    }
+    return redraw;
+}
+
+/*- SetupModeWidget: do mode widget configuration (OffTheSpot only) -*/
+static void
+SetupModeWidget(ocw, mask, value)
+OffTheSpotConversionWidget ocw;
+unsigned long mask;
+ConversionAttributes *value;
+{
+    Window clwin = ocw->ccontrol.clientwindow;
+    Widget inputobj = ocw->ccontrol.inputobj;
+    Arg shellarg[10], modearg[10], objarg[10];
+    Cardinal i = 0, j = 0, k = 0;
+
+    XtSetArg(shellarg[i], XtNparentWindow, clwin); i++;
+    XtSetArg(shellarg[i], XtNx, value->statusarea.x); i++;
+    XtSetArg(shellarg[i], XtNy, value->statusarea.y); i++;
+    XtSetArg(shellarg[i], XtNwidth, value->statusarea.width); i++;
+    XtSetArg(shellarg[i], XtNheight, value->statusarea.height); i++;
+
+    XtSetArg(modearg[j], XtNlabel, ICGetMode(inputobj)); j++;
+
+    if (mask & CAColormap) {
+	XtSetArg(modearg[j], XtNcolormap, value->colormap); j++;
+    } else {
+	XtSetArg(modearg[j], XtNcolormap,
+		 DefaultColormapOfScreen(XtScreen((Widget)ocw))); j++;
+    }
+    if (mask & CAColor) {
+	XtSetArg(modearg[j], XtNbackground, value->background); j++;
+	XtSetArg(objarg[k], XtNforeground, value->foreground); k++;
+	XtSetArg(objarg[k], XtNbackground, value->background); k++;
+    } else {
+	XtSetArg(modearg[j], XtNbackground, ocw->core.background_pixel); j++;
+    }
+
+    if (ocw->offthespot.modewidget == NULL) {
+	Widget shell, mode, disp;
+	shell = XtCreatePopupShell("modeShell", adoptedShellWidgetClass,
+				   (Widget)ocw, shellarg, i);
+	mode = XtCreateManagedWidget("mode", icLabelWidgetClass, shell,
+				     modearg, j);
+	disp = XtCreateWidget("display", ocw->ccontrol.displayobjclass, mode,
+			      objarg, k);
+	if (mask & CAStatusFonts) {
+	    CDSetFonts(disp, value->status_fonts, value->num_status_fonts);
+	}
+
+	ocw->offthespot.modeshell = shell;
+	ocw->offthespot.modewidget = mode;
+	ocw->offthespot.modedisplayobj = disp;
+	XtInstallAccelerators(mode, (Widget)ocw);
+    } else {
+	if (mask & CAStatusFonts) {
+	    CDSetFonts(ocw->offthespot.modedisplayobj,
+		       value->status_fonts, value->num_status_fonts);
+	} else {
+	    CDSetFonts(ocw->offthespot.modedisplayobj,
+		       (XFontStruct **)NULL, 0);
+	}
+	XtSetValues(ocw->offthespot.modeshell, shellarg, i);
+	XtSetValues(ocw->offthespot.modewidget, modearg, j);
+	XtSetValues(ocw->offthespot.modedisplayobj, objarg, k);
+    }
+
+    ICLRecomputeSize(ocw->offthespot.modewidget);
+}
+
+/*- ResetModeWidget: do mode widget reconfiguration (OffTheSpot only) -*/
+static Boolean
+ResetModeWidget(ocw, mask, value)
+OffTheSpotConversionWidget ocw;
+unsigned long mask;
+ConversionAttributes *value;
+{
+    Arg shellarg[10], modearg[10], objarg[10];
+    Cardinal i = 0, j = 0, k = 0;
+    Boolean redraw = False;
+
+    if (mask & CAStatusArea) {
+	XtSetArg(shellarg[i], XtNx, value->statusarea.x); i++;
+	XtSetArg(shellarg[i], XtNy, value->statusarea.y); i++;
+	XtSetArg(shellarg[i], XtNwidth, value->statusarea.width); i++;
+	XtSetArg(shellarg[i], XtNheight, value->statusarea.height); i++;
+    }
+
+    if (mask & CAColormap) {
+	XtSetArg(modearg[j], XtNcolormap, value->colormap); j++;
+	redraw = True;
+    }
+    if (mask & CAColor) {
+	XtSetArg(modearg[j], XtNbackground, value->background); j++;
+	XtSetArg(objarg[k], XtNforeground, value->foreground); k++;
+	XtSetArg(objarg[k], XtNbackground, value->background); k++;
+	redraw = True;
+    }
+    XtSetValues(ocw->offthespot.modeshell, shellarg, i);
+    XtSetValues(ocw->offthespot.modewidget, modearg, j);
+    XtSetValues(ocw->offthespot.modedisplayobj, objarg, k);
+
+    if (mask & CAStatusFonts) {
+	CDSetFonts(ocw->offthespot.modedisplayobj,
+		   value->status_fonts, value->num_status_fonts);
+	ICLRecomputeSize(ocw->offthespot.modewidget);
+	redraw = True;
+    }
+
+    return redraw;
+}
+
+/*- SetupCanvasWidget: do text canvas configuration on conversion startup -*/
+static void
+SetupCanvasWidget(ocw, mask, value)
+OffTheSpotConversionWidget ocw;
+unsigned long mask;
+ConversionAttributes *value;
+{
+    Window clwin = ocw->ccontrol.clientwindow;
+    Arg arg[10];
+    Cardinal i = 0;
+
+    XtSetArg(arg[i], XtNparentWindow, clwin); i++;
+
+    if (mask & CAClientArea) {
+	XtSetArg(arg[i], XtNx, value->clientarea.x); i++;
+	XtSetArg(arg[i], XtNy, value->clientarea.y); i++;
+	XtSetArg(arg[i], XtNwidth, value->clientarea.width); i++;
+	XtSetArg(arg[i], XtNheight, value->clientarea.height); i++;
+    } else {
+	XtSetArg(arg[i], XtNx, 0); i++;
+	XtSetArg(arg[i], XtNy, 0); i++;
+	XtSetArg(arg[i], XtNwidth, ocw->ccontrol.client_attr.width); i++;
+	XtSetArg(arg[i], XtNheight, ocw->ccontrol.client_attr.height); i++;
+    }
+
+    /* if (mask & CALineSpacing) ... */
+    if (mask & CAColormap) {
+	XtSetArg(arg[i], XtNcolormap, value->colormap); i++;
+    } else {
+	XtSetArg(arg[i], XtNcolormap,
+		 DefaultColormapOfScreen(XtScreen((Widget)ocw))); i++;
+    }
+    if (mask & CAColor) {
+	XtSetArg(arg[i], XtNbackground, value->background); i++;
+    } else {
+	XtSetArg(arg[i], XtNbackground, ocw->core.background_pixel); i++;
+    }
+    if (mask & CACursor) {
+	XtSetArg(arg[i], XtNcursor, value->cursor); i++;
+    } else {
+	XtSetArg(arg[i], XtNcursor, None); i++;
+    }
+
+    if (ocw->offthespot.canvaswidget == NULL) {
+	Widget canvas;
+	canvas = XtCreatePopupShell("text", canvasShellWidgetClass,
+				    (Widget)ocw, arg, i);
+	XtAddCallback(canvas, XtNexposeCallback, TextRedisplay, (XtPointer)ocw);
+	XtAddCallback(canvas, XtNresizeCallback, TextResize, (XtPointer)ocw);
+	XtInstallAccelerators(canvas, (Widget)ocw);
+	ocw->offthespot.canvaswidget = canvas;
+    } else {
+	XtSetValues(ocw->offthespot.canvaswidget, arg, i);
+    }
+}
+
+/*- ResetCanvasWidget: do text canvas reconfiguration on attribute change (OfftheSpot only) -*/
+static Boolean
+ResetCanvasWidget(ocw, mask, value)
+OffTheSpotConversionWidget ocw;
+unsigned long mask;
+ConversionAttributes *value;
+{
+    Arg arg[10];
+    Cardinal i = 0;
+    Boolean redraw = False;
+
+    if (mask & CAClientArea) {
+	XtSetArg(arg[i], XtNx, value->clientarea.x); i++;
+	XtSetArg(arg[i], XtNy, value->clientarea.y); i++;
+	XtSetArg(arg[i], XtNwidth, value->clientarea.width); i++;
+	XtSetArg(arg[i], XtNheight, value->clientarea.height); i++;
+	redraw = True;
+    }
+
+    if (mask & CAColormap) {
+	XtSetArg(arg[i], XtNcolormap, value->colormap); i++;
+	redraw = True;
+    }
+    if (mask & CAColor) {
+	XtSetArg(arg[i], XtNbackground, value->background); i++;
+	redraw = True;
+    }
+    if (mask & CACursor) {
+	XtSetArg(arg[i], XtNcursor, value->cursor); i++;
+    }
+
+    XtSetValues(ocw->offthespot.canvaswidget, arg, i);
+
+    return redraw;
+}
+
+static void
+UpdateText(w)
+Widget w;
+{
+    OffTheSpotConversionWidget ocw = (OffTheSpotConversionWidget)w;
+
+    TRACE(("OffTheSpotConversion:UpdateText()\n"));
+    eraseCursor(ocw);
+    computeDisplaySegments(ocw);
+    computeCursor(ocw);
+    reconfigureDisplay(ocw);
+    updateDisplay(ocw);
+    showCursor(ocw);
+}
+
+static void
+UpdateMode(w)
+Widget w;
+{
+    OffTheSpotConversionWidget ocw = (OffTheSpotConversionWidget)w;
+
+    TRACE(("OffTheSpotConversion:UpdateMode()\n"));
+    XtVaSetValues(ocw->offthespot.modewidget,
+		  XtNlabel, ICGetMode(ocw->ccontrol.inputobj),
+		  NULL);
+}
+
+static void
+SelectionControl(w, arg)
+Widget w;
+ICSelectionControlArg *arg;
+{
+    OffTheSpotConversionWidget ocw = (OffTheSpotConversionWidget)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;
+    }
+}
+
+/* ARGSUSED */
+static void
+SelectionStart(ocw, kind)
+OffTheSpotConversionWidget ocw;
+int kind;
+{
+    Cardinal ncand;
+
+    TRACE(("OffTheSpotConversion:SelectionStart()\n"));
+    if (ocw->offthespot.selectionpoppedup) {
+	TRACE(("\tselection already started -- ignored\n"));
+	return;
+    }
+
+    ocw->offthespot.candlist = ICGetItemList(ocw->ccontrol.inputobj, &ncand);
+    ocw->offthespot.numcands = ncand;
+
+    TRACE(("\tnumcands=%d\n", ocw->offthespot.numcands));
+    CPanelSetList(ocw->offthespot.selectionwidget,
+		  ocw->offthespot.candlist,
+		  ocw->offthespot.numcands, 0, True);
+
+    /* $B%]%C%W%"%C%W$9$k>l=j$r7h$a$k(B */
+    LocateSelectionPopup(ocw);
+
+    XtPopup(ocw->offthespot.selectionshell, XtGrabNone);
+    ocw->offthespot.selectionpoppedup = True;
+}
+
+static void
+LocateSelectionPopup(ocw)
+OffTheSpotConversionWidget ocw;
+{
+    Position x, y;
+    DisplayLocation lastp;
+    Dimension dpyWidth, dpyHeight;
+    Widget canvas = ocw->offthespot.canvaswidget;
+    Widget panel = ocw->offthespot.selectionwidget;
+    Widget shell = ocw->offthespot.selectionshell;
+    int clx, cly;
+    Window junk;
+    int barheight = ocw->ccontrol.titlebarheight;
+
+    if (ocw->offthespot.numsegments > 0) {
+	computeLastPosition(ocw->offthespot.dispsegments[ocw->offthespot.numsegments - 1].fragments, &lastp);
+    } else {
+	lastp.y = 0;
+    }
+    lastp.x = canvas->core.width / 2;
+    lastp.y += ocw->offthespot.lineheight;
+    (void)XTranslateCoordinates(XtDisplay(canvas), XtWindow(canvas),
+				RootWindowOfScreen(XtScreen(canvas)),
+				0, 0, &clx, &cly, &junk);
+
+    x = clx + lastp.x - panel->core.width / 2;
+    y = cly + lastp.y + 8;	/* XXX */
+
+    dpyWidth = WidthOfScreen(XtScreen(canvas));
+    dpyHeight = HeightOfScreen(XtScreen(canvas));
+
+    if (x + panel->core.width > dpyWidth) x = dpyWidth - panel->core.width;
+    if (x < 0) x = 0;
+    if (y + panel->core.height + barheight > dpyHeight) {
+	y = cly - panel->core.height - 8 - barheight;
+	if (y < 0) y = dpyHeight - panel->core.height - barheight;
+    }
+    MoveShell(shell, x, y);
+}
+
+static void
+SelectionEnd(ocw, current)
+OffTheSpotConversionWidget ocw;
+int *current;
+{
+    TRACE(("OffTheSpotConversion:SelectionEnd()\n"));
+    if (!ocw->offthespot.selectionpoppedup) {	/* for safe */
+	TRACE(("\tnot in selection mode -- ignored\n"));
+	return;
+    }
+
+    XtVaGetValues(ocw->offthespot.selectionwidget,
+		  XtNcurrentItem, current,
+		  NULL);
+
+    XtPopdown(ocw->offthespot.selectionshell);
+
+    ocw->offthespot.selectionpoppedup = False;
+}
+
+static void
+SelectionSet(ocw, current)
+OffTheSpotConversionWidget ocw;
+int current;
+{
+    TRACE(("OffTheSpotConversion:SelectionSet()\n"));
+    if (!ocw->offthespot.selectionpoppedup) {	/* for safe */
+	TRACE(("\tnot in selection mode -- ignored\n"));
+	return;
+    }
+
+    XtVaSetValues(ocw->offthespot.selectionwidget,
+		  XtNcurrentItem, current,
+		  NULL);
+}
+
+static void
+SelectionGet(ocw, current)
+OffTheSpotConversionWidget ocw;
+int *current;
+{
+    TRACE(("OffTheSpotConversion:SelectionGet()\n"));
+    if (!ocw->offthespot.selectionpoppedup) {	/* for safe */
+	TRACE(("\tnot in selection mode -- ignored\n"));
+	return;
+    }
+
+    XtVaGetValues(ocw->offthespot.selectionwidget,
+		  XtNcurrentItem, current,
+		  NULL);
+}
+
+static void
+SelectionMove(ocw, dir)
+OffTheSpotConversionWidget ocw;
+int dir;
+{
+    TRACE(("OffTheSpotConversion:SelectionMove()\n"));
+    if (!ocw->offthespot.selectionpoppedup) {	/* for safe */
+	TRACE(("\tnot in selection mode -- ignored\n"));
+	return;
+    }
+
+    CPanelMoveCurrent(ocw->offthespot.selectionwidget, dir);
+}
+
+/*
+ * Aux Callback
+ */
+
+static void
+AuxControl(w, arg)
+Widget w;
+ICAuxControlArg *arg;
+{
+    OffTheSpotConversionWidget ocw = (OffTheSpotConversionWidget)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)
+OffTheSpotConversionWidget ocw;
+{
+  ICString *auxstr;
+  Cardinal ncand, curseg, cursorpos;
+  
+  if (ocw->offthespot.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->offthespot.auxwidget, auxstr, ncand, curseg, cursorpos);
+    
+  /* $B%]%C%W%"%C%W$9$k>l=j$r7h$a$k(B */
+  LocateAuxPopup(ocw);
+
+  XtPopup(ocw->offthespot.auxshell, XtGrabNone);
+  ocw->offthespot.auxpoppedup = True;
+}
+
+/* ARGSUSED */
+static void
+AuxEnd(ocw)
+OffTheSpotConversionWidget ocw;
+{
+  if (!ocw->offthespot.auxpoppedup) return;	/* for safe */
+
+/*  APanelEnd(ocw->offthespot.auxwidget); */
+
+  XtPopdown(ocw->offthespot.auxshell);
+
+  ocw->offthespot.auxpoppedup = False;
+}
+
+/* ARGSUSED */
+static void
+AuxChange(ocw)
+OffTheSpotConversionWidget ocw;
+{
+  Cardinal ncand, curseg, cursorpos;
+  ICString *auxstr;
+
+  if (!ocw->offthespot.auxpoppedup) return;	/* for safe */
+
+  auxstr = ICGetAuxSegments(ocw->ccontrol.inputobj,
+			    &ncand, &curseg, &cursorpos);
+
+  APanelChange(ocw->offthespot.auxwidget, auxstr, ncand, curseg, cursorpos);
+}
+
+static void
+LocateAuxPopup(ocw)
+OffTheSpotConversionWidget ocw;
+{
+    Position x, y;
+    DisplayLocation lastp;
+    Dimension dpyWidth, dpyHeight;
+    Widget canvas = ocw->offthespot.canvaswidget;
+    Widget panel = ocw->offthespot.auxwidget;
+    Widget shell = ocw->offthespot.auxshell;
+    int clx, cly;
+    Window junk;
+    int barheight = ocw->ccontrol.titlebarheight;
+
+    if (ocw->offthespot.numsegments > 0) {
+	computeLastPosition(ocw->offthespot.dispsegments[ocw->offthespot.numsegments - 1].fragments, &lastp);
+    } else {
+	lastp.y = 0;
+    }
+    lastp.x = canvas->core.width / 2;
+    lastp.y += ocw->offthespot.lineheight;
+    (void)XTranslateCoordinates(XtDisplay(canvas), XtWindow(canvas),
+				RootWindowOfScreen(XtScreen(canvas)),
+				0, 0, &clx, &cly, &junk);
+
+    x = clx + lastp.x - panel->core.width / 2;
+    y = cly + lastp.y + 8;	/* XXX */
+
+    dpyWidth = WidthOfScreen(XtScreen(canvas));
+    dpyHeight = HeightOfScreen(XtScreen(canvas));
+
+    if (x + panel->core.width > dpyWidth) x = dpyWidth - panel->core.width;
+    if (x < 0) x = 0;
+    if (y + panel->core.height + barheight > dpyHeight) {
+	y = cly - panel->core.height - 8 - barheight;
+	if (y < 0) y = dpyHeight - panel->core.height - barheight;
+    }
+    MoveShell(shell, x, y);
+}
+
+
+/*
+ *+ TextCanvas callback
+ */
+
+/*- TextRedisplay: redraw text canvas -*/
+static void
+TextRedisplay(w, client_data, call_data)
+Widget w;
+XtPointer client_data;
+XtPointer call_data;
+{
+    OffTheSpotConversionWidget ocw = (OffTheSpotConversionWidget)client_data;
+    XExposeEvent *event = (XExposeEvent *)call_data;
+    XRectangle region;
+    Boolean cursorredraw;
+
+    TRACE(("OffTheSpotConversion:TextRedisplay()\n"));
+    region.x = event->x;
+    region.y = event->y;
+    region.width = event->width;
+    region.height = event->height;
+
+    cursorredraw = exposeCursor(ocw, w, &region);
+    redrawSegments(ocw, &region);
+    if (cursorredraw) showCursor(ocw);
+}
+
+/*- TextResize: do reconfiguration (and redraw) of text canvas when resized -*/
+/* ARGSUSED */
+static void
+TextResize(w, client_data, call_data)
+Widget w;
+XtPointer client_data;
+XtPointer call_data;	/* unused */
+{
+    OffTheSpotConversionWidget ocw = (OffTheSpotConversionWidget)client_data;
+
+    TRACE(("OffTheSpotConversion:TextResize()\n"));
+    recomputeDisplaySegments(ocw);
+    computeCursor(ocw);
+    if (XtIsRealized(w)) {
+	/* redraw it */
+	XClearArea(XtDisplay(w), XtWindow(w), 0, 0, 0, 0, True);
+    }
+}
+
+
+/*
+ *+ Selection Widget callback
+ */
+
+/*- SelectionSelected: selection selected callback -*/
+/* ARGSUSED */
+static void
+SelectionSelected(w, client_data, call_data)
+Widget w;
+XtPointer client_data;
+XtPointer call_data;
+{
+    OffTheSpotConversionWidget ocw = (OffTheSpotConversionWidget)client_data;
+    int current = (int)call_data;
+
+    TRACE(("OffTheSpotConversion:SelectionSelected()\n"));
+    XtPopdown(ocw->offthespot.selectionshell);
+    ocw->offthespot.selectionpoppedup = False;
+    ICSelectItem(ocw->ccontrol.inputobj, current);
+}
+
+
+/*
+ *+ text drawing functions
+ */
+
+/*- computeDisplaySegments: compare old&new text and update segments/fragments -*/
+static void
+computeDisplaySegments(ocw)
+OffTheSpotConversionWidget ocw;
+{
+    Widget inputobj = ocw->ccontrol.inputobj;
+    Cardinal nnew = ICNumSegments(inputobj);
+    Cardinal nold = ocw->offthespot.numsegments;
+    ICString *newseg;
+    DisplaySegment *dseg;
+    DisplayLocation disploc;
+    Cardinal nsame;
+    int diff;
+    Cardinal i;
+
+    TRACE(("OffTheSpotConversion:computeDisplaySegments() nnew=%d\n", nnew));
+    allocDisplaySegments(ocw, nnew);
+
+    initialLocation(ocw, &disploc);
+
+    for (i = 0, dseg = ocw->offthespot.dispsegments; i < nnew; i++, dseg++) {
+	newseg = ICGetSegment(ocw->ccontrol.inputobj, i);
+	if (i >= nold) {
+	    copyString(newseg, &dseg->seg);
+	    dseg->redrawpos = 0;
+	    dseg->fragments = computeDisplayFragments(ocw, newseg, &disploc);
+	} else {
+	    DisplayFragment *oldfragments, *newfragments;
+
+	    dseg->redrawpos = -1;
+	    diff = ICCompareSegment(inputobj, newseg, &dseg->seg, &nsame);
+	    if (diff != ICSame ||
+		disploc.x != dseg->fragments->region.x ||
+		disploc.y != dseg->fragments->region.y) {
+		oldfragments = dseg->fragments;
+		newfragments = computeDisplayFragments(ocw, newseg, &disploc);
+		dseg->fragments = newfragments;
+	    } else {
+		oldfragments = NULL;
+		newfragments = dseg->fragments;
+		computeLastPosition(newfragments, &disploc);
+	    }
+
+	    switch (diff) {
+	    case ICSame:
+		if (oldfragments == NULL ||
+		    oldfragments->region.x == newfragments->region.x &&
+		    oldfragments->region.y == newfragments->region.y) {
+		    dseg->redrawpos = -1;
+		} else {
+		    dseg->redrawpos = 0;
+		}
+		break;
+	    case ICAttrChanged:
+		dseg->redrawpos = 0;
+		dseg->seg.attr = newseg->attr;
+		break;
+	    case ICStringChanged:
+		if (oldfragments == NULL ||
+		    oldfragments->region.x == newfragments->region.x &&
+		    oldfragments->region.y == newfragments->region.y) {
+		    dseg->redrawpos = nsame;
+		} else {
+		    dseg->redrawpos = 0;
+		}
+		freeString(&dseg->seg);
+		copyString(newseg, &dseg->seg);
+		break;
+	    default:
+		dseg->redrawpos = 0;
+		freeString(&dseg->seg);
+		copyString(newseg, &dseg->seg);
+		break;
+	    }
+	    if (oldfragments) freeDisplayFragments(oldfragments);
+	}
+    }
+
+    for (; i < nold; i++, dseg++) freeDisplaySegment(dseg);
+
+    ocw->offthespot.numsegments = nnew;
+}
+
+/*- recomputeDisplaySegments: recompute segments/fragments -*/
+static void
+recomputeDisplaySegments(ocw)
+OffTheSpotConversionWidget ocw;
+{
+    Cardinal nsegs = ocw->offthespot.numsegments;
+    DisplaySegment *dseg;
+    DisplayLocation disploc;
+    Cardinal i;
+
+    initialLocation(ocw, &disploc);
+
+    for (i = 0, dseg = ocw->offthespot.dispsegments; i < nsegs; i++, dseg++) {
+	freeDisplayFragments(dseg->fragments);
+	dseg->redrawpos = 0;
+	dseg->fragments = computeDisplayFragments(ocw, &dseg->seg, &disploc);
+    }
+}
+
+/*- computeLastPosition: get last position of the specified fragment list -*/
+static void
+computeLastPosition(fragments, disploc)
+DisplayFragment *fragments;
+DisplayLocation *disploc;
+{
+    while (fragments->next != NULL) fragments = fragments->next;
+    disploc->x = fragments->region.x + fragments->region.width;
+    disploc->y = fragments->region.y;
+}
+
+/*- computeDisplayFragments: compute fragment(s) of the specified segment -*/
+static DisplayFragment *
+computeDisplayFragments(ocw, newseg, disploc)
+OffTheSpotConversionWidget ocw;
+ICString *newseg;
+DisplayLocation *disploc;
+{
+    int start;
+    int nchars;
+    Widget dispobj = ocw->offthespot.displayobj;
+    DisplayFragment *fragments, *dfp;
+    int widthavailable;
+
+    TRACE(("computeDisplayFragments()\n"));
+    start = 0;
+    fragments = NULL;
+    while (start < newseg->nchars) {
+	widthavailable = widthAvailable(ocw, disploc);
+	nchars = CDMaxChar(dispobj, newseg, start, widthavailable);
+	if (nchars == 0 && disploc->x <= ocw->offthespot.leftmargin) {
+	    /*
+	     * avoiding infinite loop
+	     * we display at least one character per line
+	     */
+	    nchars = 1;
+	}
+	TRACE(("\twidthavailable=%d, start=%d, maxchar=%d\n", widthavailable, start, nchars));
+	if (nchars > 0) {
+	    if (fragments == NULL) {
+		fragments = dfp = allocDisplayFragment();
+	    } else {
+		dfp->next = allocDisplayFragment();
+		dfp = dfp->next;
+	    }
+	    dfp->from = start;
+	    dfp->nchars = nchars;
+	    dfp->region.x = disploc->x;
+	    dfp->region.y = disploc->y;
+	    dfp->region.width = CDStringWidth(dispobj, newseg, start,
+						    start + nchars);
+	    dfp->region.height = ocw->offthespot.lineheight;
+	    dfp->next = NULL;
+
+	    disploc->x += dfp->region.width;
+	}
+	start += nchars;
+
+	if (start < newseg->nchars) nextLocation(ocw, disploc);
+    }
+
+    return fragments;
+}
+
+/*- widthAvailable: return the width of the current line left for drawing -*/
+static int
+widthAvailable(ocw, disploc)
+OffTheSpotConversionWidget ocw;
+DisplayLocation *disploc;
+{
+    return ocw->offthespot.canvaswidget->core.width - 
+           ocw->offthespot.rightmargin - disploc->x;
+}
+
+/*- initialLocation: return the initial text drawing position -*/
+static void
+initialLocation(ocw, disploc)
+OffTheSpotConversionWidget ocw;
+DisplayLocation *disploc;
+{
+    int cheight = ocw->offthespot.canvaswidget->core.height;
+    int lheight = ocw->offthespot.lineheight;
+
+    disploc->x = ocw->offthespot.leftmargin;
+    if (cheight / lheight == 1) {
+	/* if there's space for a single line, locate it in the center */
+	disploc->y = (cheight - lheight) / 2;
+    } else {
+	disploc->y = 0;
+    }
+}
+
+/*- nextLocation: return the position of the next line -*/
+static void
+nextLocation(ocw, disploc)
+OffTheSpotConversionWidget ocw;
+DisplayLocation *disploc;
+{
+    disploc->x = ocw->offthespot.leftmargin;
+    disploc->y += ocw->offthespot.lineheight;
+}
+
+/*- findLocation: compute the display position of specific character -*/
+static DisplayLocation *
+findLocation(ocw, dsp, offset, disploc)
+OffTheSpotConversionWidget ocw;
+DisplaySegment *dsp;
+Cardinal offset;
+DisplayLocation *disploc;
+{
+    DisplayFragment *dfp = dsp->fragments;
+
+    while (dfp != NULL) {
+	if (dfp->nchars > offset ||
+	    dfp->next == NULL && dfp->nchars == offset) {
+	    break;
+	}
+	offset -= dfp->nchars;
+	dfp = dfp->next;
+    }
+    if (dfp == NULL) return NULL;
+
+    disploc->x = dfp->region.x + CDStringWidth(ocw->offthespot.displayobj,
+					       &dsp->seg, dfp->from,
+					       dfp->from + offset);
+    disploc->y = dfp->region.y;
+
+    return disploc;
+}
+
+/*- reconfigureDisplay: do reconfiguration of text canvas (resize/popup/popdown) -*/
+static void
+reconfigureDisplay(ocw)
+OffTheSpotConversionWidget ocw;
+{
+    DisplaySegment *dsp;
+    DisplayFragment *dfp;
+    Widget canvas = ocw->offthespot.canvaswidget;
+    Position lastx, lasty;
+    Dimension height = ocw->offthespot.lineheight;
+    int i;
+
+    lastx = 0;
+    dsp = ocw->offthespot.dispsegments;
+    if (ocw->offthespot.numsegments > 0 && dsp->fragments != NULL) {
+	lasty = dsp->fragments->region.y;
+    } else {
+	lasty = 0;
+    }
+    for (i = 0, dsp = ocw->offthespot.dispsegments; i < ocw->offthespot.numsegments; i++, dsp++) {
+	for (dfp = dsp->fragments; dfp != NULL; dfp = dfp->next) {
+	    if (lasty != dfp->region.y) {
+		XClearArea(XtDisplay(canvas), XtWindow(canvas),
+			   lastx, lasty, 0, height, False);
+	    }
+	    lastx = dfp->region.x + dfp->region.width;
+	    lasty = dfp->region.y;
+	}
+    }
+
+    XClearArea(XtDisplay(canvas), XtWindow(canvas),
+	       lastx, lasty, 0, 0, False);
+    if (lasty + height < canvas->core.height) {
+	XClearArea(XtDisplay(canvas), XtWindow(canvas),
+		   0, lasty + height, 0, 0, False);
+    }
+}
+
+/*- updateDisplay: redraw text (if needed) -*/
+static void
+updateDisplay(ocw)
+OffTheSpotConversionWidget ocw;
+{
+    DisplaySegment *dsp = ocw->offthespot.dispsegments;
+    int i;
+
+    for (i = 0; i < ocw->offthespot.numsegments; i++, dsp++) {
+	if (dsp->redrawpos >= 0) {
+	    TRACE(("updateDisplaySegment(seg#=%d)\n", i));
+	    updateDisplaySegment(ocw, dsp);
+	}
+    }
+}
+
+/*- updateDisplaySegment: redraw specified segment (if needed) -*/
+static void
+updateDisplaySegment(ocw, dsp)
+OffTheSpotConversionWidget ocw;
+DisplaySegment *dsp;
+{
+    DisplayFragment *dfp = dsp->fragments;
+    Widget dispobj = ocw->offthespot.displayobj;
+    Widget canvas = ocw->offthespot.canvaswidget;
+    int from;
+    int x;
+
+    while (dfp != NULL) {
+	if (dsp->redrawpos < dfp->from + dfp->nchars) {
+	    from = (dsp->redrawpos > dfp->from) ? dsp->redrawpos : dfp->from;
+	    x = dfp->region.x;
+	    if (from > dfp->from) {
+		x += CDStringWidth(dispobj, &dsp->seg, dfp->from, from);
+	    } 
+	    CDDrawString(dispobj, canvas, &dsp->seg,
+			 from, dfp->from + dfp->nchars,
+			 x, dfp->region.y);
+	}
+	dfp = dfp->next;
+    }
+}
+
+/*- redrawSegments: redraw segments in specified area -*/
+static void
+redrawSegments(ocw, region)
+OffTheSpotConversionWidget ocw;
+XRectangle *region;
+{
+    DisplaySegment *dsp = ocw->offthespot.dispsegments;
+    DisplayFragment *dfp;
+    Widget dispobj = ocw->offthespot.displayobj;
+    Widget canvas = ocw->offthespot.canvaswidget;
+    int i;
+
+    for (i = 0; i < ocw->offthespot.numsegments; i++, dsp++) {
+	for (dfp = dsp->fragments; dfp != NULL; dfp = dfp->next) {
+	    if (intersectRect(&dfp->region, region)) {
+		CDDrawString(dispobj, canvas, &dsp->seg,
+			      dfp->from, dfp->from + dfp->nchars,
+			      dfp->region.x, dfp->region.y);
+	    }
+	}
+    }
+}
+
+/*
+ *+ insert cursor handling
+ */
+
+/*- eraseCursor: erase insert cursor -*/
+static void
+eraseCursor(ocw)
+OffTheSpotConversionWidget ocw;
+{
+    if (!ocw->offthespot.cursorvisible) return;
+
+    TRACE(("eraseCursor() at (%d,%d)\n",
+	    ocw->offthespot.cursorlocation.x,
+	    ocw->offthespot.cursorlocation.y));
+    CDDrawCursor(ocw->offthespot.displayobj,
+		 ocw->offthespot.canvaswidget,
+		 ocw->offthespot.cursorlocation.x,
+		 ocw->offthespot.cursorlocation.y,
+		 False);
+    ocw->offthespot.cursorvisible = False;
+}
+
+/*- showCursor: draw insert cursor -*/
+static void
+showCursor(ocw)
+OffTheSpotConversionWidget ocw;
+{
+    if (!ocw->offthespot.cursorvisible) return;
+
+    TRACE(("showCursor at (%d,%d)\n",
+	    ocw->offthespot.cursorlocation.x,
+	    ocw->offthespot.cursorlocation.y));
+    CDDrawCursor(ocw->offthespot.displayobj,
+		 ocw->offthespot.canvaswidget,
+		 ocw->offthespot.cursorlocation.x,
+		 ocw->offthespot.cursorlocation.y,
+		 True);
+}
+
+/*- exposeCursor: make the insert cursor redraw correctly when exposing -*/
+static Boolean
+exposeCursor(ocw, w, region)
+OffTheSpotConversionWidget ocw;
+Widget w;
+XRectangle *region;
+{
+    XRectangle bounds;
+
+    if (!ocw->offthespot.cursorvisible) return False;
+
+    TRACE(("exposeCursor(region=%d,%d-%d,%d)\n",
+	    region->x, region->y, region->width, region->height));
+    CDGetCursorBounds(ocw->offthespot.displayobj, &bounds);
+    bounds.x += ocw->offthespot.cursorlocation.x;
+    bounds.y += ocw->offthespot.cursorlocation.y;
+    if (intersectRect(region, &bounds)) {
+	eraseCursor(ocw);
+	XClearArea(XtDisplay(w), XtWindow(w),
+		   bounds.x, bounds.y, bounds.width, bounds.height, False);
+	unionRect(region, &bounds, region);
+    }
+    ocw->offthespot.cursorvisible = True;
+    return True;
+}
+
+/*- computeCursor: compute cursor position -*/
+static void
+computeCursor(ocw)
+OffTheSpotConversionWidget ocw;
+{
+    DisplaySegment *dsp;
+    DisplayLocation disploc;
+    Cardinal seg, offset;
+
+    if (ocw->offthespot.numsegments == 0) {
+	/* special case */
+	initialLocation(ocw, &(ocw->offthespot.cursorlocation));
+	ocw->offthespot.cursorlocation.y += ocw->offthespot.ascent;
+	ocw->offthespot.cursorvisible = True;
+	return;
+    }
+
+    if (!ICCursorPos(ocw->ccontrol.inputobj, &seg, &offset)) return;
+
+    /* sanity check */
+    if (seg >= ocw->offthespot.numsegments) return;
+    dsp = ocw->offthespot.dispsegments + seg;
+    if (offset > dsp->seg.nchars) return;
+
+    if (findLocation(ocw, dsp, offset, &disploc) == NULL) return;
+
+    disploc.y += ocw->offthespot.ascent;
+
+    ocw->offthespot.cursorvisible = True;
+    ocw->offthespot.cursorlocation = disploc;
+}
+
+/*
+ *+ miscelaneous functions
+ */
+
+/*- 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);
+}
+
+/*- intersectRect: return whether given two rectangles have a intersection -*/
+static Boolean
+intersectRect(rect1, rect2)
+register XRectangle *rect1;
+register XRectangle *rect2;
+{
+    return (rect1->x + rect1->width <= rect2->x ||
+	    rect1->x >= rect2->x + rect2->width ||
+	    rect1->y + rect1->height <= rect2->y ||
+	    rect1->y >= rect2->y + rect2->height) ? False : True;
+}
+
+/*- unionRect: returns a minimum rectangle that covers given two rectangles -*/
+static void
+unionRect(rect1, rect2, rect_ret)
+register XRectangle *rect1;
+register XRectangle *rect2;
+XRectangle *rect_ret;
+{
+    int x0, x1, y0, y1;
+
+    x0 = (rect1->x > rect2->x) ? rect2->x : rect1->x;
+    y0 = (rect1->y > rect2->y) ? rect2->y : rect1->y;
+    x1 = (rect1->x + rect1->width > rect2->x + rect2->width) ?
+		rect1->x + rect1->width : rect2->x + rect2->width;
+    y1 = (rect1->y + rect1->height > rect2->y + rect2->height) ?
+		rect1->y + rect1->height : rect2->y + rect2->height;
+
+    rect_ret->x = x0;
+    rect_ret->y = y0;
+    rect_ret->width = x1 - x0;
+    rect_ret->height = y1 - y0;
+}
+
+static DisplayFragment *free_fragments = NULL;
+
+/*- allocDisplayFragment: get a new fragment -*/
+static DisplayFragment *
+allocDisplayFragment()
+{
+    if (free_fragments == NULL) {
+	return XtNew(DisplayFragment);
+    } else {
+	DisplayFragment *dfp = free_fragments;
+	free_fragments = dfp->next;
+	return dfp;
+    }
+}
+
+/*- freeDisplayFragments: add specified fragment list to the free-list -*/
+static void
+freeDisplayFragments(fragments)
+DisplayFragment *fragments;
+{
+    DisplayFragment *dfp = fragments;
+
+    if (dfp == NULL) return;
+    while (dfp->next != NULL) dfp = dfp->next;
+    dfp->next = free_fragments;
+    free_fragments = fragments;
+}
+
+/*- destroyDisplayFragments: do 'free()' specified fragment list -*/
+static void
+destroyDisplayFragments(fragments)
+DisplayFragment *fragments;
+{
+    DisplayFragment *dfp;
+
+    while (fragments != NULL) {
+	dfp = fragments->next;
+	XtFree((char *)fragments);
+	fragments = dfp;
+    }
+}
+
+/*- allocDisplaySegments: prepare specified number of display segments -*/
+static void
+allocDisplaySegments(ocw, n)
+OffTheSpotConversionWidget ocw;
+Cardinal n;
+{
+    if (ocw->offthespot.dispsegmentsize > n) return;
+    n = ((n + 3) / 4) * 4 ;
+    if (ocw->offthespot.dispsegments == NULL) {
+	ocw->offthespot.dispsegments = (DisplaySegment *)XtMalloc(n * sizeof(DisplaySegment));
+    } else {
+	ocw->offthespot.dispsegments = (DisplaySegment *)XtRealloc((char *)ocw->offthespot.dispsegments, n * sizeof(DisplaySegment));
+    }
+    ocw->offthespot.dispsegmentsize = n;
+}
+
+/*- freeDisplaySegment: free display segment's contents -*/
+static void
+freeDisplaySegment(dsp)
+DisplaySegment *dsp;
+{
+    freeString(&dsp->seg);
+    freeDisplayFragments(dsp->fragments);
+    dsp->fragments = NULL;
+}
+
+/*- clearAllDisplaySegments: clear all display segment's -*/
+static void
+clearAllDisplaySegments(ocw)
+OffTheSpotConversionWidget ocw;
+{
+    DisplaySegment *dsp = ocw->offthespot.dispsegments;
+    int i;
+
+    for (i = 0; i < ocw->offthespot.numsegments; i++) {
+	freeDisplaySegment(dsp++);
+    }
+    ocw->offthespot.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;
+}