diff lib/OverConv.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/OverConv.c	Mon Mar 08 04:44:30 2010 +0900
@@ -0,0 +1,2708 @@
+#ifndef lint
+static char *rcsid = "$Id: OverConv.c,v 1.71 1999/05/06 09:07:58 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
+ */
+
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+#include <X11/Xmu/CharSet.h>
+#if XtSpecificationRelease > 4
+#include <X11/Xfuncs.h>
+#endif
+#include "CachedAtom.h"
+#include "AsyncErr.h"
+#include "OverConvP.h"
+#include "InputConv.h"
+#include "ConvDisp.h"
+#include "CandPanel.h"
+#include "AuxPanel.h"
+#include "CanvasShel.h"
+#include "ICLabel.h"
+
+#define DEBUG_VAR debug_OverTheSpotConversion
+#include "DebugPrint.h"
+
+typedef enum { NeedNone, NeedRedraw, NeedReconfig } ResetStatus;
+
+/*- resource table -*/
+static XtResource resources[] = {
+#define offset(field) XtOffset(OverTheSpotConversionWidget, overthespot.field)
+    { XtNspotX, XtCPosition, XtRPosition, sizeof(Position),
+	offset(spotx), XtRImmediate, (XtPointer)0 },
+    { XtNspotY, XtCPosition, XtRPosition, sizeof(Position),
+	offset(spoty), XtRImmediate, (XtPointer)0 },
+    { XtNautoSpotForwarding, XtCAutoSpotForwarding, XtRBoolean, sizeof(Boolean),
+	offset(spotforwarding), XtRImmediate, (XtPointer)False },
+    { XtNlineSpacing, XtCLineSpacing, XtRDimension, sizeof(Dimension),
+	offset(linespacing), XtRImmediate, (XtPointer)0 },
+    { XtNmodeLocation, XtCModeLocation, XtRModeLocation, sizeof(ModeLocation),
+	offset(modelocation), XtRString, "BottomLeft" },
+    { XtNshrinkWindow, XtCShrinkWindow, XtRBoolean, sizeof(Boolean),
+	offset(shrinkwindow), XtRImmediate, (XtPointer)False },
+    { XtNignoreStatusAreaSpec, XtCIgnoreStatusAreaSpec,
+	XtRBoolean, sizeof(Boolean),
+	offset(ignorestatusarea), XtRImmediate, (XtPointer)False },
+    { XtNmodeBorderForeground, XtCModeBorderForeground,
+	XtRBoolean, sizeof(Boolean),
+	offset(borderforeground), XtRImmediate, (XtPointer)False },
+    { XtNuseOverrideShellForMode, XtCUseOverrideShellForMode,
+	XtRBoolean, sizeof(Boolean),
+	offset(useoverride), XtRImmediate, (XtPointer)False },
+    /* changes superclass's default */
+    { XtNmappedWhenManaged, XtCMappedWhenManaged, XtRBoolean, sizeof(Boolean),
+	XtOffset(OverTheSpotConversionWidget, core.mapped_when_managed),
+	XtRImmediate, (XtPointer)False },
+#undef offset
+};
+
+/*- default translation table -*/
+static char translations[] = "<Key>: to-inputobj()";	/* same as superclass's */
+
+/*- declarations of static functions -*/
+static void ClassInitialize();
+static void Initialize();
+static void Destroy();
+static Boolean SetValues();
+
+static void ConversionStartup();
+static void ChangeAttributes();
+static void ChangeFocus();
+static void ConversionFinish();
+
+static void CreateDisplayObject();
+static void CreateSelectionWidget();
+static void CreateModeWidget();
+static TextCanvas * CreateTextCanvas();
+
+static void setupTextCanvas();
+static ResetStatus resetTextCanvas();
+static void setupDisplayObject();
+static ResetStatus resetDisplayObject();
+static void setupModeWidget();
+static ResetStatus resetModeWidget();
+static void locateTextCanvasInitial();
+static void locateModeWidget();
+static void locateTrackingModeWidget();
+static void redrawAndReconfigureTextCanvas();
+
+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 void ForwardSpot();
+
+static void CreateAuxWidget();
+static void AuxControl();
+static void AuxStart();
+static void locateAuxPopup();
+static void AuxEnd();
+static void AuxChange();
+
+
+static void TextRedisplay();
+
+static void SelectionSelected();
+
+static void computeDisplaySegments();
+static void recomputeDisplaySegments();
+static void computeLastPosition();
+static DisplayFragment *computeDisplayFragments();
+static int computeWidthAvailable();
+static void nextLocation();
+static DisplayLocation *findLocation();
+static void reconfigureDisplay();
+static void updateDisplay();
+static void updateDisplaySegment();
+static void redrawSegments();
+
+static void adjustDisplay();
+static Boolean getAttributeSegmentRange();
+static Boolean getInsertingSegmentRange();
+static void adjustOffset();
+
+static void eraseCursor();
+static void showCursor();
+static Boolean exposeCursor();
+static void computeCursor();
+
+static void StringToModeLocation();
+
+static void MoveShell();
+static Window getToplevelWindow();
+static void setTransientFor();
+static void setMwmHints();
+static void getFocusOffset();
+static Boolean intersectRect();
+static void unionRect();
+static int enoughSpaceForStatus();
+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,
+};
+
+/*- overTheSpotConversionClass record -*/
+OverTheSpotConversionClassRec overTheSpotConversionClassRec = {
+  { /* core fields */
+    /* superclass		*/	(WidgetClass)&conversionControlClassRec,
+    /* class_name		*/	"OverTheSpotConversion",
+    /* widget_size		*/	sizeof(OverTheSpotConversionRec),
+    /* 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			*/	XtInheritFix,
+    /* ModeChange		*/	UpdateMode,
+    /* SelectionControl		*/	SelectionControl,
+    /* SelectionControl		*/	AuxControl,
+  },
+  { /* overTheSpotConversion fields */
+    /* empty			*/	0
+  },
+};
+
+WidgetClass overTheSpotConversionWidgetClass = (WidgetClass)&overTheSpotConversionClassRec;
+
+/*
+ *+ Convenience macros
+ */
+#define SPOTX(w)	((w)->overthespot.spotx)
+#define SPOTY(w)	((w)->overthespot.spoty)
+#define CLAREA(w)	((w)->overthespot.clientarea)
+#define FOCUSOFFX(w)	((w)->overthespot.focusoffsetx)
+#define FOCUSOFFY(w)	((w)->overthespot.focusoffsety)
+
+/*
+ *+ Core class methods
+ */
+
+/*- ClassInitialize: add resource converter (string->modelocation) -*/
+/* ARGSUSED */
+static void
+ClassInitialize()
+{
+    XtAddConverter(XtRString, XtRModeLocation, StringToModeLocation,
+		   NULL, 0);
+}
+
+/*- Initialize: initialize method -*/
+/* ARGSUSED */
+static void
+Initialize(req, new, args, num_args)
+Widget req;
+Widget new;
+ArgList args;
+Cardinal *num_args;
+{
+    OverTheSpotConversionWidget ocw = (OverTheSpotConversionWidget)new;
+
+    ocw->overthespot.background = ocw->core.background_pixel;
+    ocw->overthespot.canvaslist = NULL;
+    ocw->overthespot.overflowcanvas = NULL;
+    ocw->overthespot.dispsegments = NULL;
+    ocw->overthespot.numsegments = 0;
+    ocw->overthespot.dispsegmentsize = 0;
+    ocw->overthespot.candlist = NULL;
+    ocw->overthespot.numcands = 0;
+    ocw->overthespot.selectionpoppedup = False;
+    ocw->overthespot.cursorvisible = False;
+    ocw->overthespot.canvascursor = None;
+    ocw->overthespot.auxpoppedup = False;
+
+    ocw->overthespot.wm_state =
+      CachedInternAtom(XtDisplay(new), "WM_STATE", False);
+
+    /* $B%F%-%9%HI=<($N(B widget $B$O:G=i$NJQ493+;O;~$K:n$k(B */
+    CreateDisplayObject(ocw);
+    CreateSelectionWidget(ocw);
+    CreateAuxWidget(ocw);
+    CreateModeWidget(ocw);
+}
+
+/*- Destroy: destroy method -*/
+static void
+Destroy(w)
+Widget w;
+{
+    OverTheSpotConversionWidget ocw = (OverTheSpotConversionWidget)w;
+
+    /* $B%G%#%9%W%l%$%;%0%a%s%H$NNN0h$r2rJ|(B */
+    if (ocw->overthespot.dispsegments) {
+	DisplaySegment *dsp = ocw->overthespot.dispsegments;
+	int i;
+
+	for (i = 0; i < ocw->overthespot.numsegments; i++) {
+	    freeString(&dsp[i].seg);
+	    destroyDisplayFragments(dsp->fragments);
+	}
+	XtFree((char *)dsp);
+    }
+
+    /* canvaslist $B$NNN0h$r2rJ|(B (canvas widget $B$O(B $B<+F0E*$K(B destroy $B$5$l$k(B */
+    if (ocw->overthespot.canvaslist) {
+	TextCanvas *p = ocw->overthespot.canvaslist;
+	while (p) {
+	    TextCanvas *q = p->next;
+	    XtFree((char *)p);
+	    p = q;
+	}
+    }
+}
+
+/*- SetValues: setvalues method -*/
+/* ARGSUSED */
+static Boolean
+SetValues(cur, req, new, args, num_args)
+Widget cur;
+Widget req;
+Widget new;
+ArgList args;
+Cardinal *num_args;
+{
+    /* OverTheSpotConversionWidget ocw = (OverTheSpotConversionWidget)new; */
+    return False;
+}
+
+/*
+ *+ ConversionControl cass methods
+ */
+
+/*- ConversionStartup: class specific conversion startup -*/
+static void
+ConversionStartup(w, mask, value)
+Widget w;
+unsigned long mask;
+ConversionAttributes *value;
+{
+    OverTheSpotConversionWidget ocw = (OverTheSpotConversionWidget)w;
+    Widget inputobj = ocw->ccontrol.inputobj;
+    Window toplevel;
+
+    TRACE(("OverTheSpot:ConversionStartup()\n"));
+
+    /* $BFbIt$N%P%C%U%!$r%/%j%"$9$k(B */
+    clearAllDisplaySegments(ocw);
+
+    /* $BJQ49%*%V%8%'%/%H$K%3!<%k%P%C%/$r@_Dj$9$k(B */
+    XtAddCallback(inputobj, XtNfixNotify, ForwardSpot, (XtPointer)w);
+
+    if (ocw->overthespot.ignorestatusarea) mask &= ~CAStatusArea;
+
+    setupDisplayObject(ocw, mask, value);
+    setupTextCanvas(ocw, mask, value);
+    setupModeWidget(ocw, mask, value);
+
+    /* WM_TRANSIENT_FOR $B%W%m%Q%F%#$r@5$7$/%;%C%H$9$k(B */
+    toplevel = getToplevelWindow(XtDisplay(w),
+				 ocw->ccontrol.clientwindow,
+				 ocw->overthespot.wm_state);
+    setTransientFor(ocw->overthespot.modeshell, toplevel);
+    setTransientFor(ocw->overthespot.selectionshell, toplevel);
+    setTransientFor(ocw->overthespot.auxshell, toplevel);
+
+    /* $B%F%-%9%H%-%c%s%P%9$NI=<(0LCV$r7h$a$k(B */
+    locateTextCanvasInitial(ocw);
+
+    /* $B%b!<%I$NI=<(0LCV$r7h$a$k(B */
+    if (!ocw->overthespot.modelocationspecified) locateModeWidget(ocw);
+
+    /*
+     * OverTheSpotConvesion $B$N>l9g!"<+J,<+?H$O%]%C%W%"%C%W$7$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!"(BRealize $B$@$1$7$F$*$/(B
+     * $B$=$N:]!"Bg$-$5$r;XDj$7$J$$$H%5%$%:$,(B 0 $B$K$J$C$F$7$^$&$N$GCm0U$9$k(B
+     */
+    if (!XtIsRealized(w)) {
+	Arg args[2];
+
+	XtSetArg(args[0], XtNwidth, 1);
+	XtSetArg(args[1], XtNheight, 1);
+	XtSetValues(w, args, 2);
+	XtRealizeWidget(w);
+    }
+
+    /* $B%b!<%II=<(%-%c%s%P%9$r%]%C%W%"%C%W$9$k(B */
+    if (ocw->overthespot.modeshell != NULL) {
+	XtPopup(ocw->overthespot.modeshell, XtGrabNone);
+    }
+}
+
+/*- ChangeAttributes: class specific conversion attribute change routine -*/
+/* ARGSUSED */
+static void
+ChangeAttributes(w, mask, value)
+Widget w;
+unsigned long mask;
+ConversionAttributes *value;
+{
+    OverTheSpotConversionWidget ocw = (OverTheSpotConversionWidget)w;
+    ResetStatus dispres, tcres;
+
+    TRACE(("OverTheSpot:ChangeAttributes()\n"));
+
+    if (ocw->overthespot.ignorestatusarea) mask &= ~CAStatusArea;
+
+    dispres = resetDisplayObject(ocw, mask, value);
+    tcres = resetTextCanvas(ocw, mask, value);
+    if (dispres == NeedReconfig || tcres == NeedReconfig) {
+	redrawAndReconfigureTextCanvas(ocw);
+    } else if (dispres == NeedRedraw || tcres == NeedRedraw) {
+	TextCanvas *tcp = ocw->overthespot.canvaslist;
+
+	while (tcp != NULL) {
+	    if (XtIsRealized(tcp->canvas)) {
+		XClearArea(XtDisplay(tcp->canvas), XtWindow(tcp->canvas),
+			   0, 0, 0, 0, True);
+	    }
+	    tcp = tcp->next;
+	}
+    }
+
+    if (resetModeWidget(ocw, mask, value) != NeedNone &&
+	XtIsRealized(ocw->overthespot.modewidget)) {
+	XClearArea(XtDisplay(w), XtWindow((Widget)ocw->overthespot.modewidget),
+		   0, 0, 0, 0, True);
+    }
+}
+
+/*- ChangeFocus: class specific conversion attribute change routine -*/
+static void
+ChangeFocus(w, set)
+Widget w;
+int set;
+{
+    OverTheSpotConversionWidget ocw = (OverTheSpotConversionWidget)w;
+
+    TRACE(("OverTheSpot:ChangeFocus()\n"));
+
+    if (ocw->overthespot.modeshell == NULL) return;
+    if (set) {
+	XtPopup(ocw->overthespot.modeshell, XtGrabNone);
+    } else {
+	XtPopdown(ocw->overthespot.modeshell);
+    }
+}
+
+/*- ConversionFinish: class specific conversion finish -*/
+/* ARGSUSED */
+static void
+ConversionFinish(w)
+Widget w;
+{
+    OverTheSpotConversionWidget ocw = (OverTheSpotConversionWidget)w;
+    Widget inputobj = ocw->ccontrol.inputobj;
+    TextCanvas *tcp = ocw->overthespot.canvaslist;
+    XAEHandle h;
+
+    /* $BJQ49%*%V%8%'%/%H$N%3!<%k%P%C%/$r>C$9(B */
+    XtRemoveCallback(inputobj, XtNfixNotify, ForwardSpot, (XtPointer)w);
+
+    /* Popdown and unrealize textcanvases
+     *	we must be careful here. if clientwindow are destroyed,
+     *	the text canvases are also destroyed.
+     *	we have to popdown and unrealize canvas 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));
+    while (tcp != NULL) {
+	if (tcp->poppedup) XtPopdown(tcp->canvas);
+	XtUnrealizeWidget(tcp->canvas);
+	/* XtVaSetValues(tcp->canvas, XtNcursor, None, NULL); */
+	tcp->poppedup = False;
+	tcp = tcp->next;
+    }
+    /* Popdown mode widget */
+    if (ocw->overthespot.modeshell != NULL) {
+	XtPopdown(ocw->overthespot.modeshell);
+    }
+    if (ocw->overthespot.modeshell == ocw->overthespot.modeshell_fix) {
+	XtUnrealizeWidget(ocw->overthespot.modeshell);
+    }
+    XAEUnset(h);
+
+    /* Popdown selection popup (if popped-up) */
+    if (ocw->overthespot.selectionpoppedup) {
+	XtPopdown(ocw->overthespot.selectionshell);
+	ocw->overthespot.selectionpoppedup = False;
+    }
+    if (ocw->overthespot.auxpoppedup) {
+	XtPopdown(ocw->overthespot.auxshell);
+	ocw->overthespot.auxpoppedup = False;
+    }
+}
+
+/*
+ *+ sub-widget creation
+ */
+
+/*- CreateDisplayObject: create display object for text drawing -*/
+static void
+CreateDisplayObject(ocw)
+OverTheSpotConversionWidget ocw;
+{
+    Widget dispobj;
+
+    dispobj = XtCreateWidget("displayObj", ocw->ccontrol.displayobjclass,
+			     (Widget)ocw, NULL, 0);
+
+    ocw->overthespot.displayobj = dispobj;
+    ocw->overthespot.lineheight = CDLineHeight(dispobj,
+					       &ocw->overthespot.ascent);
+
+}
+
+/*- CreateSelectionWidget: create selection widget for selecting candidates -*/
+static void
+CreateSelectionWidget(ocw)
+OverTheSpotConversionWidget ocw;
+{
+    Widget shell, sel, obj;
+
+    shell = XtVaCreatePopupShell("selectionShell",
+				 transientShellWidgetClass,
+				 (Widget)ocw,
+				 XtNwidth, 1, XtNheight, 1,
+				 NULL);
+    ocw->overthespot.selectionshell = shell;
+
+    sel = XtCreateManagedWidget("selection", candidatePanelWidgetClass,
+				shell, NULL, 0);
+    obj = XtCreateWidget("display", ocw->ccontrol.displayobjclass,
+			 sel, NULL, 0);
+    XtAddCallback(sel, XtNcallback, SelectionSelected, (Widget)ocw);
+    XtInstallAccelerators(sel, (Widget)ocw);
+
+    ocw->overthespot.selectionwidget = sel;
+    ocw->overthespot.selectiondisplayobj = obj;
+}
+
+/*- CreateAuxWidget: create auxiliary widget for displaying auxiliary data -*/
+static void
+CreateAuxWidget(ocw)
+OverTheSpotConversionWidget ocw;
+{
+    Widget shell, sel, obj;
+
+    shell = XtVaCreatePopupShell("auxShell",
+				 transientShellWidgetClass,
+				 (Widget)ocw,
+				 XtNwidth, 1, XtNheight, 1,
+				 XtNallowShellResize, True,
+				 NULL);
+    ocw->overthespot.auxshell = shell;
+
+    sel = XtCreateManagedWidget("aux", auxPanelWidgetClass,
+				shell, NULL, 0);
+    obj = XtCreateWidget("display", ocw->ccontrol.displayobjclass,
+			 sel, NULL, 0);
+    XtAddCallback(sel, XtNcallback, SelectionSelected, (Widget)ocw);
+    XtInstallAccelerators(sel, (Widget)ocw);
+
+    ocw->overthespot.auxwidget = sel;
+    ocw->overthespot.auxdisplayobj = obj;
+}
+
+/*- CreateModeWidget: create mode displaying widget -*/
+static void
+CreateModeWidget(ocw)
+OverTheSpotConversionWidget ocw;
+{
+    Widget shell, w, obj;
+
+    TRACE(("CreateModeWidget()\n"));
+
+    /* create fixed widget */
+    shell = XtCreatePopupShell("modeShell", adoptedShellWidgetClass,
+			       (Widget)ocw, NULL, 0);
+    XtVaGetValues(shell, XtNborderWidth, &ocw->overthespot.saved_bw, NULL);
+    w = XtCreateManagedWidget("mode", icLabelWidgetClass, shell, NULL, 0);
+    obj = XtCreateWidget("display", ocw->ccontrol.displayobjclass, w,
+			 NULL, 0);
+    XtInstallAccelerators(shell, (Widget)ocw);
+    XtInstallAccelerators(w, (Widget)ocw);
+    ocw->overthespot.modeshell_fix = shell;
+    ocw->overthespot.modewidget_fix = w;
+    ocw->overthespot.modedisplayobj_fix = obj;
+
+    /* create floating widget */
+    if (ocw->overthespot.useoverride) {
+	shell = XtCreatePopupShell("modeShell", overrideShellWidgetClass,
+				   (Widget)ocw, NULL, 0);
+    } else {
+	shell = XtCreatePopupShell("modeShell", transientShellWidgetClass,
+				   (Widget)ocw, NULL, 0);
+    }
+    w = XtCreateManagedWidget("mode", icLabelWidgetClass, shell, NULL, 0);
+    obj = XtCreateWidget("display", ocw->ccontrol.displayobjclass, w,
+			 NULL, 0);
+    XtInstallAccelerators(shell, (Widget)ocw);
+    XtInstallAccelerators(w, (Widget)ocw);
+    ocw->overthespot.modeshell_float = shell;
+    ocw->overthespot.modewidget_float = w;
+    ocw->overthespot.modedisplayobj_float = obj;
+
+    /* set mwm hints for the shell */
+    setMwmHints(shell);
+}
+
+/*- CreateTextCanvas: create a text canvas -*/
+static TextCanvas *
+CreateTextCanvas(ocw)
+OverTheSpotConversionWidget ocw;
+{
+    TextCanvas *tcp;
+
+    tcp = XtNew(TextCanvas);
+    tcp->x = 0;
+    tcp->y = 0;
+    tcp->poppedup = False;
+    tcp->next = NULL;
+    tcp->canvas = XtVaCreatePopupShell("text",
+				       canvasShellWidgetClass,
+				       (Widget)ocw,
+				       XtNcolormap,
+				           ocw->overthespot.colormap,
+				       XtNbackground,
+				           ocw->overthespot.background,
+				       XtNparentWindow,
+				           ocw->ccontrol.clientwindow,
+				       XtNoverrideRedirect, True,
+				       NULL);	/* XXX for now XXX */
+    XtAddCallback(tcp->canvas, XtNexposeCallback, TextRedisplay, (XtPointer)ocw);
+    XtInstallAccelerators(tcp->canvas, (Widget)ocw);
+
+    return tcp;
+}
+
+
+/*
+ *+ subwidget configuration
+ */
+
+/*- setupTextCanvas: do text canvas configuration on conversion startup -*/
+static void
+setupTextCanvas(ocw, mask, value)
+OverTheSpotConversionWidget ocw;
+unsigned long mask;
+ConversionAttributes *value;
+{
+    TRACE(("setupTextCanvas(mask=0x%lx)\n", mask));
+
+    getFocusOffset(ocw);
+
+    if (mask & CAClientArea) {
+	CLAREA(ocw) = value->clientarea;
+    } else {
+	/* default */
+	CLAREA(ocw).x = 0;
+	CLAREA(ocw).y = 0;
+	CLAREA(ocw).width = ocw->ccontrol.focus_attr.width;
+	CLAREA(ocw).height = ocw->ccontrol.focus_attr.height;
+    }
+    CLAREA(ocw).x += FOCUSOFFX(ocw);
+    CLAREA(ocw).y += FOCUSOFFY(ocw);
+
+    TRACE(("\tclientarea: (%d,%d)-(%d,%d)\n",CLAREA(ocw).x,CLAREA(ocw).y,CLAREA(ocw).width,CLAREA(ocw).height));
+    if (mask & CASpotLocation) {
+	SPOTX(ocw) = value->spotx + FOCUSOFFX(ocw);
+	SPOTY(ocw) = value->spoty + FOCUSOFFY(ocw);
+    } else {
+	/* default */
+	SPOTX(ocw) = CLAREA(ocw).x;
+	SPOTY(ocw) = CLAREA(ocw).y + ocw->overthespot.ascent;
+    }
+    TRACE(("\tspotlocation: (%d,%d)\n",SPOTX(ocw),SPOTY(ocw)));
+
+    if (mask & CALineSpacing) {
+	ocw->overthespot.linespacing = value->linespacing;
+	if (ocw->overthespot.linespacing == 0) {
+	    DPRINT(("\tspecified linespacing is 0. reset to default\n"));
+	    ocw->overthespot.linespacing = ocw->overthespot.lineheight;
+	}
+    } else {
+	ocw->overthespot.linespacing = ocw->overthespot.lineheight;
+    }
+    if (mask & CAColormap) {
+	ocw->overthespot.colormap = value->colormap;
+    } else {
+	ocw->overthespot.colormap = DefaultColormapOfScreen(XtScreen((Widget)ocw));
+    }
+    if (mask & CAColor) {
+	ocw->overthespot.background = value->background;
+    } else {
+	/* default */
+	ocw->overthespot.background = ocw->core.background_pixel;
+    }
+    if (mask & CACursor) {
+	ocw->overthespot.canvascursor = value->cursor;
+    } else {
+	ocw->overthespot.canvascursor = None;
+    }
+
+    if (ocw->overthespot.canvaslist == NULL) {
+	ocw->overthespot.canvaslist = CreateTextCanvas(ocw);
+    } else {
+	TextCanvas *tcp = ocw->overthespot.canvaslist;
+	while (tcp != NULL) {
+	    XtVaSetValues(tcp->canvas,
+			  XtNcolormap, ocw->overthespot.colormap,
+			  XtNbackground, ocw->overthespot.background,
+			  XtNparentWindow, ocw->ccontrol.clientwindow,
+			  XtNcursor, ocw->overthespot.canvascursor,
+			  NULL);
+	    tcp = tcp->next;
+	}
+    }
+}
+
+/*- resetTextCanvas: do text canvas reconfiguration on attribute change -*/
+static ResetStatus
+resetTextCanvas(ocw, mask, value)
+OverTheSpotConversionWidget ocw;
+unsigned long mask;
+ConversionAttributes *value;
+{
+    ResetStatus redraw = NeedNone;
+
+    if (mask & (CAColormap|CAColor|CACursor)) {
+	Arg args[3];
+	Cardinal i = 0;
+	if (mask & CAColormap &&
+	    value->colormap != ocw->overthespot.colormap) {
+	    ocw->overthespot.colormap = value->colormap;
+	    XtSetArg(args[i], XtNcolormap, value->colormap); i++;
+	}
+	if (mask & CAColor &&
+	    value->background != ocw->overthespot.background) {
+	    ocw->overthespot.background = value->background;
+	    XtSetArg(args[i], XtNbackground, value->background); i++;
+	}
+	if (mask & CACursor &&
+	    value->cursor != ocw->overthespot.canvascursor) {
+	    ocw->overthespot.canvascursor = value->cursor;
+	    XtSetArg(args[i], XtNcursor, value->cursor); i++;
+	}
+	if (i > 0) {
+	    TextCanvas *tcp = ocw->overthespot.canvaslist;
+
+	    while (tcp != NULL) {
+		XtSetValues(tcp->canvas, args, i);
+		tcp = tcp->next;
+	    }
+	    redraw = NeedRedraw;
+	}
+    }
+    if (mask & CAFocusWindow) {
+	getFocusOffset(ocw);
+	redraw = NeedReconfig;
+    }
+    if (mask & CAClientArea) {
+	if (value->clientarea.x + FOCUSOFFX(ocw) != CLAREA(ocw).x ||
+	    value->clientarea.y + FOCUSOFFY(ocw) != CLAREA(ocw).y ||
+	    value->clientarea.width != CLAREA(ocw).width ||
+	    value->clientarea.height != CLAREA(ocw).height) {
+	    CLAREA(ocw) = value->clientarea;
+	    CLAREA(ocw).x += FOCUSOFFX(ocw);
+	    CLAREA(ocw).y += FOCUSOFFY(ocw);
+	    redraw = NeedReconfig;
+	}
+    } else if (mask & CAFocusWindow) {
+	CLAREA(ocw).x = FOCUSOFFX(ocw);
+	CLAREA(ocw).y = FOCUSOFFY(ocw);
+	CLAREA(ocw).width = ocw->ccontrol.focus_attr.width;
+	CLAREA(ocw).height = ocw->ccontrol.focus_attr.height;
+    }
+    if (mask & CASpotLocation) {
+	if (value->spotx + FOCUSOFFX(ocw) != SPOTX(ocw) ||
+	    value->spoty + FOCUSOFFY(ocw) != SPOTY(ocw)) {
+	    SPOTX(ocw) = value->spotx + FOCUSOFFX(ocw);
+	    SPOTY(ocw) = value->spoty + FOCUSOFFY(ocw);
+	    redraw = NeedReconfig;
+	}
+    } else if (mask & CAFocusWindow) {
+	SPOTX(ocw) = CLAREA(ocw).x;
+	SPOTY(ocw) = CLAREA(ocw).y + ocw->overthespot.ascent;
+    }
+    if (mask & CALineSpacing) {
+	if (value->linespacing != ocw->overthespot.linespacing &&
+	    value->linespacing != 0) {
+	    ocw->overthespot.linespacing = value->linespacing;
+	    redraw = NeedReconfig;
+	}
+    } else if (mask & CAFonts) {
+	ocw->overthespot.linespacing = ocw->overthespot.lineheight;
+	redraw = NeedReconfig;
+    }
+
+    return redraw;
+}
+
+/*- setupDisplayObject: do displayobj configuration on conversion startup -*/
+static void
+setupDisplayObject(ocw, mask, value)
+OverTheSpotConversionWidget ocw;
+unsigned long mask;
+ConversionAttributes *value;
+{
+    Widget dispobj = ocw->overthespot.displayobj;
+
+    TRACE(("setupDisplayObject()\n"));
+
+    /*
+     * 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) {
+	TRACE(("\tchanging fonts...\n"));
+	CDSetFonts(dispobj, value->fonts, value->num_fonts);
+    } else {
+	/* reset to default */
+	CDSetFonts(dispobj, (XFontStruct **)NULL, 0);
+    }
+    if (mask & CAColor) {
+	TRACE(("\tchanging colors...\n"));
+	XtVaSetValues(dispobj,
+		      XtNforeground, value->foreground,
+		      XtNbackground, value->background,
+		      NULL);
+    }
+    ocw->overthespot.lineheight = CDLineHeight(dispobj,
+					       &ocw->overthespot.ascent);
+}
+
+/*- resetDisplayObject: do displayobj reconfiguration on attribute change -*/
+static ResetStatus
+resetDisplayObject(ocw, mask, value)
+OverTheSpotConversionWidget ocw;
+unsigned long mask;
+ConversionAttributes *value;
+{
+    Widget dispobj = ocw->overthespot.displayobj;
+    ResetStatus redraw = NeedNone;
+
+    TRACE(("resetDisplayObject()\n"));
+
+    if (mask & CAColor) {
+	TRACE(("\tchanging colors...\n"));
+	XtVaSetValues(dispobj,
+		      XtNforeground, value->foreground,
+		      XtNbackground, value->background,
+		      NULL);
+	redraw = NeedRedraw;
+    }
+    if (mask & CAFonts) {
+	TRACE(("\tchanging fonts...\n"));
+	CDSetFonts(dispobj, value->fonts, value->num_fonts);
+	ocw->overthespot.lineheight = CDLineHeight(dispobj,
+						   &ocw->overthespot.ascent);
+	redraw = NeedReconfig;
+    }
+
+    return redraw;
+}
+
+/*- setupModeWidget: do mode widget configuration on conversion startup -*/
+static void
+setupModeWidget(ocw, mask, value)
+OverTheSpotConversionWidget ocw;
+unsigned long mask;
+ConversionAttributes *value;
+{
+    Widget inputobj = ocw->ccontrol.inputobj;
+    Widget dispobj;
+    Widget mode;
+    Arg modeargs[10];
+    Arg shellargs[15];
+    Cardinal i = 0, j = 0;
+
+    TRACE(("setupModeWidget()\n"));
+
+    /* choose appropriate widgets */
+    if (mask & CAStatusArea) {
+	/* use fixed modedisplay */
+	ocw->overthespot.modeshell = ocw->overthespot.modeshell_fix;
+	ocw->overthespot.modewidget = ocw->overthespot.modewidget_fix;
+	ocw->overthespot.modedisplayobj = ocw->overthespot.modedisplayobj_fix;
+	XtSetArg(shellargs[j], XtNparentWindow, ocw->ccontrol.clientwindow); j++;
+	XtSetArg(shellargs[j], XtNborderWidth, 0); j++;
+	XtSetArg(shellargs[j], XtNallowShellResize, False); j++;
+	XtSetArg(shellargs[j], XtNx, value->statusarea.x); j++;
+	XtSetArg(shellargs[j], XtNy, value->statusarea.y); j++;
+	XtSetArg(shellargs[j], XtNwidth, value->statusarea.width); j++;
+	XtSetArg(shellargs[j], XtNheight, value->statusarea.height); j++;
+	ocw->overthespot.modelocationspecified = True;
+    } else if (ocw->overthespot.modelocation == ModeTrackText &&
+	       enoughSpaceForStatus(ocw)) {
+	ocw->overthespot.modeshell = ocw->overthespot.modeshell_fix;
+	ocw->overthespot.modewidget = ocw->overthespot.modewidget_fix;
+	ocw->overthespot.modedisplayobj = ocw->overthespot.modedisplayobj_fix;
+	ocw->overthespot.modelocationspecified = False;
+	XtSetArg(shellargs[j], XtNparentWindow, ocw->ccontrol.clientwindow); j++;
+	XtSetArg(shellargs[j], XtNallowShellResize, True); j++;
+	XtSetArg(shellargs[j], XtNborderWidth, ocw->overthespot.saved_bw); j++;
+    } else if (ocw->overthespot.modelocation == ModeNone) {
+	ocw->overthespot.modeshell = NULL;
+	ocw->overthespot.modewidget = NULL;
+	ocw->overthespot.modedisplayobj = NULL;
+	ocw->overthespot.modelocationspecified = False;
+	return;
+    } else {
+	/* use floating modedisplay */
+	ocw->overthespot.modeshell = ocw->overthespot.modeshell_float;
+	ocw->overthespot.modewidget = ocw->overthespot.modewidget_float;
+	ocw->overthespot.modedisplayobj = ocw->overthespot.modedisplayobj_float;
+	ocw->overthespot.modelocationspecified = False;
+    }
+
+    mode = ocw->overthespot.modewidget;
+    dispobj = ocw->overthespot.modedisplayobj;
+
+    XtSetArg(modeargs[i], XtNlabel, ICGetMode(inputobj)); i++;
+    if (mask & CAColormap) {
+	XtSetArg(modeargs[i], XtNcolormap, value->colormap); i++;
+    }
+    /* ignore background_pixmap... */
+
+    /*
+     * order of changing display object resources is important.
+     * see comment in setupDisplayObject() for details.
+     */
+    if (mask & CAStatusFonts) {
+	TRACE(("\tchanging fonts...\n"));
+	CDSetFonts(dispobj, value->status_fonts, value->num_status_fonts);
+    } else {
+	/* reset to default */
+	CDSetFonts(dispobj, (XFontStruct **)NULL, 0);
+    }
+    if (mask & CAColor) {
+	TRACE(("\tchanging colors...\n"));
+	XtVaSetValues(dispobj,
+		      XtNforeground, value->foreground,
+		      XtNbackground, value->background,
+		      NULL);
+	XtSetArg(modeargs[i], XtNbackground, value->background); i++;
+	if (ocw->overthespot.borderforeground) {
+	    XtSetArg(shellargs[j], XtNborderColor, value->foreground); j++;
+	}
+    } else {
+	XtSetArg(modeargs[i], XtNbackground, ocw->overthespot.background); i++;
+    }
+
+    XtSetValues(mode, modeargs, i);
+    ICLRecomputeSize(mode);
+
+    if (!(mask & CAStatusArea)) {
+	/*
+	 * force shell to resize.
+	 * it is because Shell doesn't honor its child's dimension
+	 * at second (or later)  realization.
+	 */
+	XtSetArg(shellargs[j], XtNwidth, mode->core.width); j++;
+	XtSetArg(shellargs[j], XtNheight, mode->core.height); j++;
+    }
+    XtSetValues(ocw->overthespot.modeshell, shellargs, j);
+}
+
+/*- resetModeWidget: do mode widget reconfiguration on attribute change -*/
+static ResetStatus
+resetModeWidget(ocw, mask, value)
+OverTheSpotConversionWidget ocw;
+unsigned long mask;
+ConversionAttributes *value;
+{
+    Widget mode = ocw->overthespot.modewidget;
+    Widget dispobj = ocw->overthespot.modedisplayobj;
+    ResetStatus redraw = NeedNone;
+
+    TRACE(("resetModeWidget()\n"));
+
+    if (ocw->overthespot.modeshell == NULL) return NeedNone;
+
+    if (mask & CAStatusArea) {
+	if (ocw->overthespot.modelocationspecified &&
+	    ocw->overthespot.modeshell == ocw->overthespot.modeshell_fix) {
+	    XtVaSetValues(ocw->overthespot.modeshell,
+			  XtNx, value->statusarea.x,
+			  XtNy, value->statusarea.y,
+			  XtNwidth, value->statusarea.width,
+			  XtNheight, value->statusarea.height,
+			  NULL);
+	} /* else ignore... */
+    }
+
+    if (mask & CAColormap) {
+	XtVaSetValues(mode, XtNcolormap, value->colormap, NULL);
+    }
+
+    if (mask & CAColor) {
+	TRACE(("\tchanging colors...\n"));
+	XtVaSetValues(dispobj,
+		      XtNforeground, value->foreground,
+		      XtNbackground, value->background,
+		      NULL);
+	XtVaSetValues(mode, XtNbackground, value->background, NULL);
+	if (ocw->overthespot.borderforeground) {
+	    XtVaSetValues(ocw->overthespot.modeshell,
+			  XtNborderColor, value->foreground,
+			  NULL);
+	}
+	redraw = NeedRedraw;
+    }
+    if (mask & CAStatusFonts) {
+	TRACE(("\tchanging fonts...\n"));
+	CDSetFonts(dispobj, value->status_fonts, value->num_status_fonts);
+	ICLRecomputeSize(mode);
+	redraw = NeedRedraw;
+    }
+
+    return redraw;
+}
+
+/*- locateTextCanvasInitial: put the text canvas at the initial position -*/
+static void
+locateTextCanvasInitial(ocw)
+OverTheSpotConversionWidget ocw;
+{
+    TextCanvas *tcp = ocw->overthespot.canvaslist;
+
+    tcp->x = SPOTX(ocw);
+    tcp->y = SPOTY(ocw) - ocw->overthespot.ascent;
+}
+
+/*- locateModeWidget: put the mode widget at the initial position -*/
+static void
+locateModeWidget(ocw)
+OverTheSpotConversionWidget ocw;
+{
+    Position x, y;
+    Widget modewidget = ocw->overthespot.modewidget;
+    Widget modeshell = ocw->overthespot.modeshell;
+    int rootx, rooty;
+    Window child;
+
+    if (modeshell == ocw->overthespot.modeshell_fix) {
+	/* must be tracking text type */
+	locateTrackingModeWidget(ocw, True, 0, 0);
+	return;
+    }
+
+    switch (ocw->overthespot.modelocation) {
+    case ModeTopLeft:
+	x = 0;
+	y = -(modewidget->core.height + modeshell->core.border_width * 2);
+	y -= ocw->ccontrol.titlebarheight;
+	break;
+    case ModeTopRight:
+	x = ocw->ccontrol.client_attr.width - modewidget->core.width + modeshell->core.border_width * 2;
+	y = -(modewidget->core.height + modeshell->core.border_width * 2);
+	y -= ocw->ccontrol.titlebarheight;
+	break;
+    case ModeBottomRight:
+	x = ocw->ccontrol.client_attr.width - modewidget->core.width + modeshell->core.border_width * 2;
+	y = ocw->ccontrol.client_attr.height;
+	break;
+    case ModeTrackText:	/* in case of insufficient space in the client area */
+	x = CLAREA(ocw).x;
+	y = CLAREA(ocw).y + CLAREA(ocw).height + 2;
+	break;
+    case ModeBottomLeft:
+	x = 0;
+	y = ocw->ccontrol.client_attr.height;
+	break;
+    default:
+	/* ModeNone */
+	return;
+    }
+
+    (void)XTranslateCoordinates(XtDisplay(ocw), ocw->ccontrol.clientwindow,
+				RootWindowOfScreen(XtScreen(ocw)),
+				x, y, &rootx, &rooty, &child);
+    MoveShell(ocw->overthespot.modeshell, rootx, rooty);
+}
+
+/*- locateTrackingModeWidget: put the tracking text type mode widget at appropriate position */
+static void
+locateTrackingModeWidget(ocw, initial, x, y)
+OverTheSpotConversionWidget ocw;
+Boolean initial;
+Position x;
+Position y;
+{
+    Widget modewidget = ocw->overthespot.modewidget;
+    Widget modeshell = ocw->overthespot.modeshell;
+    Dimension width, height;
+    XRectangle *clarea = &CLAREA(ocw);
+    static Position lastx, lasty;
+
+    if (initial) {
+	x = SPOTX(ocw);
+	y = SPOTY(ocw) - ocw->overthespot.ascent
+		+ ocw->overthespot.lineheight;
+    } else if (x == lastx && y == lasty) {
+	return;
+    }
+
+    lastx = x;
+    lasty = y;
+
+    width = modewidget->core.width + modeshell->core.border_width * 2;
+    height = modewidget->core.height + modeshell->core.border_width * 2;
+
+    /* adjust x */
+    if (x + width > clarea->x + clarea->width) {
+	x = clarea->x + clarea->width - width;
+    }
+    if (x < clarea->x) x = clarea->x;
+
+    /* adjust y */
+    if (y + height + 2 <= clarea->y + clarea->height) {
+	y += 2;	/* make some (2pixels high) space between text and mode */
+    } else if (y + height > clarea->y + clarea->height) {
+	Position initx, inity;
+
+	if (initial) {
+	    initx = SPOTX(ocw);
+	    inity = SPOTY(ocw) - ocw->overthespot.ascent;
+	} else {
+	    TextCanvas *tcp = ocw->overthespot.canvaslist;
+	    initx = tcp->x;
+	    inity = tcp->y;
+	}
+	if (inity - height > clarea->y) {
+	    y = inity - height;
+	} else if (x + width < initx) {
+	    y = inity - modeshell->core.border_width * 2;
+	} else if (clarea->x + width < initx) {
+	    x = initx - width;
+	    y = inity - modeshell->core.border_width * 2;
+	} else {
+	    x = initx - width;
+	    y = inity - height;
+	}
+	if (y < clarea->y) y = clarea->y;
+    }
+    XtMoveWidget(modeshell, x, y);
+}
+
+/*- redrawAndReconfigureTextCanvas: redraw & reconfigure text canvas -*/
+static void
+redrawAndReconfigureTextCanvas(ocw)
+OverTheSpotConversionWidget ocw;
+{
+    TextCanvas *tcp = ocw->overthespot.canvaslist;
+
+    TRACE(("OverTheSpotConversion:redrawAndReconfigureTextCanvas()\n"));
+
+    /* popdown and clear all canvases */
+    while (tcp != NULL) {
+	if (tcp->poppedup) XtPopdown(tcp->canvas);
+	tcp->poppedup = False;
+	if (XtIsRealized(tcp->canvas)) {
+	    XClearArea(XtDisplay(tcp->canvas), XtWindow(tcp->canvas),
+		       0, 0, 0, 0, True);
+	}
+	tcp = tcp->next;
+    }
+    locateTextCanvasInitial(ocw);
+    recomputeDisplaySegments(ocw);
+    computeCursor(ocw);
+    reconfigureDisplay(ocw);
+}
+
+/*
+ *+ inputobject callback
+ */
+
+/*- UpdateText: update text -*/
+static void
+UpdateText(w)
+Widget w;
+{
+    OverTheSpotConversionWidget ocw = (OverTheSpotConversionWidget)w;
+
+    TRACE(("OverTheSpotConversion:UpdateText()\n"));
+    eraseCursor(ocw);
+    computeDisplaySegments(ocw);
+    computeCursor(ocw);
+    reconfigureDisplay(ocw);
+    updateDisplay(ocw);
+    showCursor(ocw);
+}
+
+/*- UpdateMode: update mode -*/
+static void
+UpdateMode(w)
+Widget w;
+{
+    OverTheSpotConversionWidget ocw = (OverTheSpotConversionWidget)w;
+
+    if (ocw->overthespot.modewidget == NULL) return;
+
+    XtVaSetValues(ocw->overthespot.modewidget,
+		  XtNlabel, ICGetMode(ocw->ccontrol.inputobj),
+		  NULL);
+#ifdef notdef
+    /* a hack... */
+    if (ocw->overthespot.modeshell == ocw->overthespot.modeshell_float &&
+	XtIsRealized(ocw->overthespot.modeshell)) {
+	XRaiseWindow(XtDisplay(ocw->overthespot.modeshell),
+		     XtWindow(ocw->overthespot.modeshell));
+    }
+#endif
+}
+
+/*- SelectionControl: selection control -*/
+static void
+SelectionControl(w, arg)
+Widget w;
+ICSelectionControlArg *arg;
+{
+    OverTheSpotConversionWidget ocw = (OverTheSpotConversionWidget)w;
+
+    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:
+	XtAppWarning(XtWidgetToApplicationContext(w),
+		     "OverTheSpotConversion: unknown selection control command");
+	break;
+    }
+}
+
+/*- SelectionStart: selection startup -*/
+/* ARGSUSED */
+static void
+SelectionStart(ocw, kind)
+OverTheSpotConversionWidget ocw;
+int kind;
+{
+    Cardinal ncand;
+
+    TRACE(("OverTheSpotConversion:SelectionStart()\n"));
+    if (ocw->overthespot.selectionpoppedup) {
+	DPRINT(("\tselection already started -- ignored\n"));
+	return;
+    }
+
+    ocw->overthespot.candlist = ICGetItemList(ocw->ccontrol.inputobj, &ncand);
+    ocw->overthespot.numcands = ncand;
+
+    TRACE(("\tnumcands=%d\n", ocw->overthespot.numcands));
+    CPanelSetList(ocw->overthespot.selectionwidget,
+		  ocw->overthespot.candlist,
+		  ocw->overthespot.numcands, 0, True);
+
+    locateSelectionPopup(ocw);
+    XtPopup(ocw->overthespot.selectionshell, XtGrabNone);
+    ocw->overthespot.selectionpoppedup = True;
+}
+
+/*- locateSelectionPopup: put selection popup at an appropriate position -*/
+static void
+locateSelectionPopup(ocw)
+OverTheSpotConversionWidget ocw;
+{
+    Position x, y;
+    int clx, cly;
+    Dimension dpyWidth, dpyHeight;
+    Widget panel = ocw->overthespot.selectionwidget;
+    Widget shell = ocw->overthespot.selectionshell;
+    Window junk;
+    int barheight = ocw->ccontrol.titlebarheight;
+
+    (void)XTranslateCoordinates(XtDisplay(ocw),
+				ocw->ccontrol.clientwindow,
+				RootWindowOfScreen(XtScreen(ocw)),
+				0, 0, &clx, &cly, &junk);
+
+    if (ocw->overthespot.numsegments > 0) {
+	DisplayLocation lastp;
+	DisplaySegment *dsp = ocw->overthespot.dispsegments;
+	int i;
+	int offset = 0;
+
+	/* find current segment. if not found, use last segment */
+	for (i = 0; i < ocw->overthespot.numsegments - 1; i++) {
+	    if (dsp[i].seg.attr & ICAttrCurrentSegment) break;
+	}
+
+	computeLastPosition(dsp[i].fragments, &lastp);
+	if (lastp.canvas == ocw->overthespot.overflowcanvas) {
+	    offset = ocw->overthespot.overflowoffset;
+	}
+	x = clx + lastp.canvas->x + lastp.x
+	  - panel->core.width / 2 + offset;
+	y = cly + lastp.canvas->y + lastp.y + ocw->overthespot.lineheight;
+    } else {
+	x = clx + SPOTX(ocw) - panel->core.width / 2;
+	y = cly + SPOTY(ocw);
+    }
+
+    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 (y + panel->core.height + barheight > (int)dpyHeight) {
+	y = cly + SPOTY(ocw) - panel->core.height - barheight;
+	if (y < 0) y = dpyHeight - panel->core.height - barheight;
+    }
+    MoveShell(shell, x, y);
+}
+
+/*- SelectionEnd: selection finish -*/
+static void
+SelectionEnd(ocw, current)
+OverTheSpotConversionWidget ocw;
+int *current;
+{
+    TRACE(("OverTheSpotConversion:SelectionEnd()\n"));
+
+    if (!ocw->overthespot.selectionpoppedup) {	/* for safe */
+	TRACE(("\tnot in selection mode -- ignored\n"));
+	return;
+    }
+
+    XtVaGetValues(ocw->overthespot.selectionwidget,
+		  XtNcurrentItem, current,
+		  NULL);
+
+    XtPopdown(ocw->overthespot.selectionshell);
+
+    ocw->overthespot.selectionpoppedup = False;
+}
+
+/*- SelectionSet: set current selection item -*/
+static void
+SelectionSet(ocw, current)
+OverTheSpotConversionWidget ocw;
+int current;
+{
+    TRACE(("OverTheSpotConversion:SelectionSet()\n"));
+
+    if (!ocw->overthespot.selectionpoppedup) {	/* for safe */
+	TRACE(("\tnot in selection mode -- ignored\n"));
+	return;
+    }
+
+    XtVaSetValues(ocw->overthespot.selectionwidget,
+		  XtNcurrentItem, current,
+		  NULL);
+}
+
+/*- SelectionGet: get current selection item -*/
+static void
+SelectionGet(ocw, current)
+OverTheSpotConversionWidget ocw;
+int *current;
+{
+    TRACE(("OverTheSpotConversion:SelectionGet()\n"));
+
+    if (!ocw->overthespot.selectionpoppedup) {	/* for safe */
+	TRACE(("\tnot in selection mode -- ignored\n"));
+	return;
+    }
+
+    XtVaGetValues(ocw->overthespot.selectionwidget,
+		  XtNcurrentItem, current,
+		  NULL);
+}
+
+/*- SelectionMove: move crrent selection to specified direction -*/
+static void
+SelectionMove(ocw, dir)
+OverTheSpotConversionWidget ocw;
+int dir;
+{
+    TRACE(("OverTheSpotConversion:SelectionMove()\n"));
+
+    if (!ocw->overthespot.selectionpoppedup) {	/* for safe */
+	TRACE(("\tnot in selection mode -- ignored\n"));
+	return;
+    }
+
+    CPanelMoveCurrent(ocw->overthespot.selectionwidget, dir);
+}
+
+/*- ForwardSpot: forward spot location when text is fixed -*/
+/* ARGSUSED */
+static void
+ForwardSpot(w, client_data, call_data)
+Widget w;
+XtPointer client_data;
+XtPointer call_data;
+{
+    OverTheSpotConversionWidget ocw = (OverTheSpotConversionWidget)client_data;
+    DisplaySegment *dsp = ocw->overthespot.dispsegments;
+    Cardinal nsegs = ocw->overthespot.numsegments;
+    DisplayLocation disploc;
+
+    if (!ocw->overthespot.spotforwarding || nsegs == 0) return;
+
+    /* get next spot location */
+    computeLastPosition(dsp[nsegs - 1].fragments, &disploc);
+
+    SPOTX(ocw) = disploc.canvas->x + disploc.x;
+    SPOTY(ocw) = disploc.canvas->y + disploc.y + ocw->overthespot.ascent;
+    locateTextCanvasInitial(ocw);
+}
+
+/*
+ * Aux Callback
+ */
+
+static void
+AuxControl(w, arg)
+Widget w;
+ICAuxControlArg *arg;
+{
+    OverTheSpotConversionWidget ocw = (OverTheSpotConversionWidget)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)
+OverTheSpotConversionWidget ocw;
+{
+  ICString *auxstr;
+  Cardinal ncand, curseg, cursorpos;
+  
+  if (ocw->overthespot.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->overthespot.auxwidget, auxstr, ncand, curseg, cursorpos);
+
+  /* $B%]%C%W%"%C%W$9$k>l=j$r7h$a$k(B */
+  locateAuxPopup(ocw, False);
+  
+  XtPopup(ocw->overthespot.auxshell, XtGrabNone);
+  ocw->overthespot.auxpoppedup = True;
+}
+
+/* ARGSUSED */
+static void
+AuxEnd(ocw)
+OverTheSpotConversionWidget ocw;
+{
+  if (!ocw->overthespot.auxpoppedup) return;	/* for safe */
+
+/*  APanelEnd(ocw->overthespot.auxwidget); */
+
+  XtPopdown(ocw->overthespot.auxshell);
+
+  ocw->overthespot.auxpoppedup = False;
+}
+
+/* ARGSUSED */
+static void
+AuxChange(ocw)
+OverTheSpotConversionWidget ocw;
+{
+  Cardinal ncand, curseg, cursorpos;
+  ICString *auxstr;
+
+  if (!ocw->overthespot.auxpoppedup) return;	/* for safe */
+
+  auxstr = ICGetAuxSegments(ocw->ccontrol.inputobj,
+			    &ncand, &curseg, &cursorpos);
+
+  APanelChange(ocw->overthespot.auxwidget, auxstr, ncand, curseg, cursorpos);
+
+  /* reposition popup shell */
+  locateAuxPopup(ocw, True);
+}
+
+/*- locateAuxPopup: put aux popup at an appropriate position -*/
+static void
+locateAuxPopup(ocw, usecurloc)
+OverTheSpotConversionWidget ocw;
+Boolean usecurloc;	/* use the current location as the default */
+{
+    int x, y;
+    int clx, cly;
+    int dpyWidth, dpyHeight;
+    Widget panel = ocw->overthespot.auxwidget;
+    Widget shell = ocw->overthespot.auxshell;
+    Window junk;
+    int barheight = ocw->ccontrol.titlebarheight;
+
+    (void)XTranslateCoordinates(XtDisplay(ocw),
+				ocw->ccontrol.clientwindow,
+				RootWindowOfScreen(XtScreen(ocw)),
+				0, 0, &clx, &cly, &junk);
+
+    if (usecurloc) {
+	x = shell->core.x;
+	y = shell->core.y;
+    } else {
+	if (ocw->overthespot.numsegments > 0) {
+	    DisplayLocation lastp;
+	    DisplaySegment *dsp = ocw->overthespot.dispsegments;
+	    int i;
+	    int offset;
+	    
+	    /* find current segment. if not found, use last segment */
+	    for (i = 0; i < ocw->overthespot.numsegments - 1; i++) {
+		if (dsp[i].seg.attr & ICAttrCurrentSegment) break;
+	    }
+	    
+	    computeLastPosition(dsp[i].fragments, &lastp);
+	    if (lastp.canvas == ocw->overthespot.overflowcanvas)
+		offset = ocw->overthespot.overflowoffset;
+	    else
+		offset = 0;
+	    x = clx + lastp.canvas->x + lastp.x
+		- panel->core.width / 2 + offset;
+	    y = cly + lastp.canvas->y + lastp.y + ocw->overthespot.lineheight;
+	} else {
+	    x = clx + ocw->overthespot.spotx - panel->core.width / 2;
+	    y = cly + ocw->overthespot.spoty;
+	}
+    }
+
+    dpyWidth = (int)WidthOfScreen(XtScreen(shell));
+    dpyHeight = (int)HeightOfScreen(XtScreen(shell));
+
+    if ((int)(x + panel->core.width) > dpyWidth) x = dpyWidth - panel->core.width;
+    if (x < 0) x = 0;
+    if ((int)(y + panel->core.height + barheight) > dpyHeight) {
+	y = cly + ocw->overthespot.spoty - panel->core.height - 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;
+{
+    OverTheSpotConversionWidget ocw = (OverTheSpotConversionWidget)client_data;
+    XExposeEvent *event = (XExposeEvent *)call_data;
+    XRectangle region;
+    Boolean cursorredraw;
+
+    TRACE(("OverTheSpotConversion: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, w, &region);
+    if (cursorredraw) showCursor(ocw);
+}
+
+
+/*
+ *+ Selection Widget callback
+ */
+
+/*- SelectionSelected: selection selected callback -*/
+/* ARGSUSED */
+static void
+SelectionSelected(w, client_data, call_data)
+Widget w;
+XtPointer client_data;
+XtPointer call_data;
+{
+    OverTheSpotConversionWidget ocw = (OverTheSpotConversionWidget)client_data;
+    int current = (int)call_data;
+
+    TRACE(("OverTheSpotConversion:SelectionSelected()\n"));
+    XtPopdown(ocw->overthespot.selectionshell);
+    ocw->overthespot.selectionpoppedup = False;
+    ICSelectItem(ocw->ccontrol.inputobj, current);
+}
+
+
+/*
+ *+ text drawing functions
+ */
+
+/*- computeDisplaySegments: compare old&new text and update segments/fragments -*/
+static void
+computeDisplaySegments(ocw)
+OverTheSpotConversionWidget ocw;
+{
+    Widget inputobj = ocw->ccontrol.inputobj;
+    int nnew = ICNumSegments(inputobj);
+    int nold = ocw->overthespot.numsegments;
+    ICString *newseg;
+    DisplaySegment *dseg;
+    DisplayLocation disploc;
+    Cardinal nsame;
+    int diff;
+    int i;
+
+    TRACE(("OverTheSpotConversion:computeDisplaySegments() nnew=%d\n", nnew));
+    allocDisplaySegments(ocw, nnew);
+
+    ocw->overthespot.overflowcanvas = NULL;
+
+    disploc.x = disploc.y = 0;
+    if (ocw->overthespot.canvaslist == NULL) {
+	ocw->overthespot.canvaslist = CreateTextCanvas(ocw);
+    }
+    disploc.canvas = ocw->overthespot.canvaslist;
+
+    for (i = 0, dseg = ocw->overthespot.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.canvas != dseg->fragments->canvas ||
+		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->canvas == newfragments->canvas &&
+		    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->canvas == newfragments->canvas &&
+		    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->overthespot.numsegments = nnew;
+}
+
+/*- recomputeDisplaySegments: recompute segments/fragments -*/
+static void
+recomputeDisplaySegments(ocw)
+OverTheSpotConversionWidget ocw;
+{
+    int nseg = ocw->overthespot.numsegments;
+    DisplaySegment *dseg;
+    DisplayLocation disploc;
+    int i;
+
+    ocw->overthespot.overflowcanvas = NULL;
+
+    disploc.x = disploc.y = 0;
+    if (ocw->overthespot.canvaslist == NULL) {
+	ocw->overthespot.canvaslist = CreateTextCanvas(ocw);
+    }
+    disploc.canvas = ocw->overthespot.canvaslist;
+
+    for (i = 0, dseg = ocw->overthespot.dispsegments; i < nseg; i++, dseg++) {
+	freeDisplayFragments(dseg->fragments);
+	dseg->redrawpos = 0;
+	dseg->fragments = computeDisplayFragments(ocw, &dseg->seg, &disploc);
+    }
+}
+
+/*- computeLastPosition: get last position of the specified fragment -*/
+static void
+computeLastPosition(fragments, disploc)
+DisplayFragment *fragments;
+DisplayLocation *disploc;
+{
+    while (fragments->next != NULL) fragments = fragments->next;
+    disploc->canvas = fragments->canvas;
+    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)
+OverTheSpotConversionWidget ocw;
+ICString *newseg;
+DisplayLocation *disploc;
+{
+    int start;
+    int nchars;
+    Widget dispobj = ocw->overthespot.displayobj;
+    DisplayFragment *fragments, *dfp;
+    int widthavailable;
+
+    TRACE(("computeDisplayFragments()\n"));
+    start = 0;
+    fragments = NULL;
+    while (start < newseg->nchars) {
+	widthavailable = computeWidthAvailable(ocw, disploc);
+	nchars = CDMaxChar(dispobj, newseg, start, widthavailable);
+	if (nchars == 0) {
+	    if (disploc->canvas->x <= CLAREA(ocw).x &&
+		disploc->x == 0) {
+		/*
+		 * specified width is too narrow to display a character.
+		 * we force to 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->canvas = disploc->canvas;
+	    dfp->region.x = disploc->x;
+	    dfp->region.y = disploc->y;
+	    dfp->region.width = CDStringWidth(dispobj, newseg, start,
+						    start + nchars);
+	    dfp->region.height = ocw->overthespot.lineheight;
+	    dfp->next = NULL;
+
+	    disploc->x += dfp->region.width;
+	}
+	start += nchars;
+	if (start < newseg->nchars) nextLocation(ocw, disploc);
+    }
+
+    return fragments;
+}
+
+/*- computeWidthAvailable: return the width of the current line left for drawing -*/
+/* ARGSUSED */
+static int
+computeWidthAvailable(ocw, disploc)
+OverTheSpotConversionWidget ocw;
+DisplayLocation *disploc;
+{
+    XRectangle *cregion = &CLAREA(ocw);
+
+    if (disploc->canvas == ocw->overthespot.overflowcanvas) {
+	 /* we pretend this canvas is veeeeeeery wide */
+	return 9999;
+    }
+    return (cregion->x + cregion->width) - (disploc->canvas->x + disploc->x);
+}
+
+/*- nextLocation: return the position of the next line -*/
+/* ARGSUSED */
+static void
+nextLocation(ocw, disploc)
+OverTheSpotConversionWidget ocw;
+DisplayLocation *disploc;
+{
+    XRectangle *cregion = &CLAREA(ocw);
+    Position x, y;
+
+    if (disploc->canvas->y + ocw->overthespot.linespacing * 2 >
+	cregion->y + cregion->height) {
+	/* no new canvas can create underneath this canvas */
+	ocw->overthespot.overflowcanvas = disploc->canvas;
+	return;
+    }
+
+    if (disploc->canvas->next == NULL) {
+	disploc->canvas->next = CreateTextCanvas(ocw);
+    }
+    x = CLAREA(ocw).x;
+    y = disploc->canvas->y + ocw->overthespot.linespacing;
+    disploc->canvas = disploc->canvas->next;
+    disploc->x = disploc->y = 0;
+
+    disploc->canvas->x = x;
+    disploc->canvas->y = y;
+}
+
+/*- findLocation: compute the display position of specified char -*/
+static DisplayLocation *
+findLocation(ocw, dsp, offset, disploc)
+OverTheSpotConversionWidget 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->canvas = dfp->canvas;
+    disploc->x = dfp->region.x + CDStringWidth(ocw->overthespot.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)
+OverTheSpotConversionWidget ocw;
+{
+    DisplaySegment *dsp;
+    DisplayFragment *dfp;
+    TextCanvas *tcp, *lasttcp;
+    Boolean shrink = ocw->overthespot.shrinkwindow;
+    XRectangle *areap = &CLAREA(ocw);
+    int i;
+
+    for (tcp = ocw->overthespot.canvaslist; tcp != NULL; tcp = tcp->next) {
+	tcp->maxx = tcp->maxy = 0;
+	tcp->shouldpopup = False;
+    }
+
+    for (i = 0, dsp = ocw->overthespot.dispsegments; i < ocw->overthespot.numsegments; i++, dsp++) {
+	for (dfp = dsp->fragments; dfp != NULL; dfp = dfp->next) {
+	    tcp = dfp->canvas;
+	    tcp->maxx = dfp->region.x + dfp->region.width;
+	    tcp->maxy = dfp->region.y + dfp->region.height;
+	    tcp->shouldpopup = True;
+	}
+    }
+
+    lasttcp = NULL;
+    for (tcp = ocw->overthespot.canvaslist; tcp != NULL; tcp = tcp->next) {
+	if (tcp->maxx < tcp->canvas->core.width && XtIsRealized(tcp->canvas)) {
+	    XClearArea(XtDisplay(tcp->canvas), XtWindow(tcp->canvas),
+		       tcp->maxx, 0, 0, 0, False);
+	}
+	if (tcp->shouldpopup) lasttcp = tcp;
+    }
+
+    if (!ocw->overthespot.modelocationspecified &&
+	ocw->overthespot.modeshell == ocw->overthespot.modeshell_fix) {
+	/* ModeTrackText */
+	if (lasttcp == NULL) {
+	    locateTrackingModeWidget(ocw, True, 0, 0);
+	} else {
+	    locateTrackingModeWidget(ocw, False, lasttcp->x,
+				     lasttcp->y + lasttcp->maxy);
+	}
+    }
+
+    if (ocw->overthespot.cursorvisible) {
+	DisplayLocation *dlp = &ocw->overthespot.cursorlocation;
+	XRectangle cbounds;
+	int x;
+
+	tcp = dlp->canvas;
+	CDGetCursorBounds(ocw->overthespot.displayobj, &cbounds);
+	x = dlp->x +  cbounds.x + cbounds.width;
+	if (x > tcp->maxx) tcp->maxx = x;
+    }
+
+    if (lasttcp != NULL &&
+	lasttcp->x + lasttcp->maxx > areap->x + areap->width) {
+	ocw->overthespot.overflowcanvas = lasttcp;
+	adjustDisplay(ocw);
+    }
+
+    for (tcp = ocw->overthespot.canvaslist; tcp != NULL; tcp = tcp->next) {
+	Arg args[2];
+	int nargs = 0;
+	if (tcp->shouldpopup && tcp->maxx > 0 && tcp->maxy > 0) {
+	    if (tcp == ocw->overthespot.overflowcanvas) {
+		XtMoveWidget(tcp->canvas,
+			     tcp->x + ocw->overthespot.overflowoffset, tcp->y);
+	    } else if (tcp->x != tcp->canvas->core.x ||
+		       tcp->y != tcp->canvas->core.y) {
+		XtMoveWidget(tcp->canvas, tcp->x, tcp->y);
+	    }
+	    if (shrink || !tcp->poppedup ||
+		tcp->maxx > tcp->canvas->core.width) {
+		XtSetArg(args[nargs], XtNwidth, tcp->maxx); nargs++;
+	    }
+	    if (!tcp->poppedup || tcp->maxy > tcp->canvas->core.height) {
+		XtSetArg(args[nargs], XtNheight, tcp->maxy); nargs++;
+	    }
+	    if (nargs > 0) XtSetValues(tcp->canvas, args, nargs);
+
+	    if (!tcp->poppedup) {
+		TRACE(("reconfigureDisplay(): canvas popup\n"));
+		XtPopup(tcp->canvas, XtGrabNone);
+		tcp->poppedup = True;
+	    }
+	} else {
+	    if (tcp->poppedup) {
+		TRACE(("reconfigureDisplay(): canvas popdown\n"));
+		XtPopdown(tcp->canvas);
+		tcp->poppedup = False;
+	    }
+	}
+    }
+}
+
+/*- updateDisplay: redraw text (if needed) -*/
+static void
+updateDisplay(ocw)
+OverTheSpotConversionWidget ocw;
+{
+    Widget dispobj = ocw->overthespot.displayobj;
+    DisplaySegment *dsp = ocw->overthespot.dispsegments;
+    int i;
+
+    for (i = 0; i < ocw->overthespot.numsegments; i++, dsp++) {
+	if (dsp->redrawpos >= 0) {
+	    TRACE(("updateDisplaySegment(seg#=%d)\n", i));
+	    updateDisplaySegment(dispobj, dsp);
+	}
+    }
+}
+
+/*- updateDisplaySegment: redraw specified segment (if needed) -*/
+static void
+updateDisplaySegment(dispobj, dsp)
+Widget dispobj;
+DisplaySegment *dsp;
+{
+    DisplayFragment *dfp = dsp->fragments;
+    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, dfp->canvas->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, canvas, region)
+OverTheSpotConversionWidget ocw;
+Widget canvas;
+XRectangle *region;
+{
+    DisplaySegment *dsp = ocw->overthespot.dispsegments;
+    DisplayFragment *dfp;
+    Widget dispobj = ocw->overthespot.displayobj;
+    int i;
+
+    for (i = 0; i < ocw->overthespot.numsegments; i++, dsp++) {
+	for (dfp = dsp->fragments; dfp != NULL; dfp = dfp->next) {
+	    if (dfp->canvas->canvas == canvas &&
+		intersectRect(&dfp->region, region)) {
+		CDDrawString(dispobj, canvas, &dsp->seg,
+			      dfp->from, dfp->from + dfp->nchars,
+			      dfp->region.x, dfp->region.y);
+	    }
+	}
+    }
+}
+
+/*
+ *+ handle overflow canvas functions
+ */
+
+/*- adjustDisplay: compute appropriate offset for the overflow canvas -*/
+static void
+adjustDisplay(ocw)
+OverTheSpotConversionWidget ocw;
+{
+    Position outerleft, outerright, innerleft, innerright;
+    TextCanvas *overflowcanvas = ocw->overthespot.overflowcanvas;
+    Cardinal curseg;
+    Cardinal curoffset;
+    XRectangle *areap;
+    Position offset;
+
+    TRACE(("adjustDisplay()\n"));
+    ocw->overthespot.overflowoffset = 0;
+
+    /*
+     * $B%9%H%i%F%8$H$7$F$O(B
+     * $B%+%l%s%H%;%0%a%s%H!&%+%l%s%H%5%V%;%0%a%s%H!&%$%s%5!<%H%+!<%=%k$N$"$k(B
+     * $B%;%0%a%s%H$N$I$l$b$J$1$l$P5$$K$7$J$$(B
+     * $B%$%s%5!<%H%+!<%=%k$,$"$l$P$=$l$r:GM%@h$9$k!#$D$^$j%$%s%5!<%H%+!<%=%k(B
+     * $B$O2?$,$"$C$F$bI=<($9$k$h$&$K$9$k!#(B
+     * $B$G$-$l$P%$%s%5!<%H%+!<%=%k$N$"$k%;%0%a%s%H$O$9$Y$FI=<($9$k!#(B
+     */
+
+    outerleft = innerleft = 9999;
+    outerright = innerright = 0;
+
+    if (ICCursorPos(ocw->ccontrol.inputobj, &curseg, &curoffset) == 1) {
+	(void)getInsertingSegmentRange(ocw, overflowcanvas,
+				       curseg, curoffset,
+				       &outerleft, &outerright, &innerleft);
+	if (outerleft <= outerright) innerright = innerleft + 2; /* XXX */
+    } else {
+	(void)getAttributeSegmentRange(ocw, overflowcanvas,
+				       ICAttrCurrentSegment,
+				       &innerleft, &innerright);
+	(void)getAttributeSegmentRange(ocw, overflowcanvas,
+				       ICAttrCurrentSubSegment,
+				       &outerleft, &outerright);
+    }
+
+    if (outerleft > outerright && innerleft > innerright) {
+	/* no important segments is on the overflow canvas */
+	TRACE(("\tno important segments on the canvas\n"));
+	return;
+    }
+
+    if (outerleft > innerleft) outerleft = innerleft;
+    if (outerright < innerright) outerright = innerright;
+
+    areap = &CLAREA(ocw);
+
+    if (areap->x <= outerleft && outerright <= areap->x + areap->width) {
+	/* important part fits in the visible area */
+	TRACE(("\timportant segments are visible\n"));
+	return;
+    }
+
+    offset = 0;
+    adjustOffset(areap, outerleft, outerright, &offset, False);
+    adjustOffset(areap, innerleft, innerright, &offset, True);
+    TRACE(("\toffset = %d\n", offset));
+    ocw->overthespot.overflowoffset = offset;
+}
+
+/*- getAttributeSegmentRange: compute span of segments which has the specified attributes -*/
+static Boolean
+getAttributeSegmentRange(ocw, canvas, attr, leftp, rightp)
+OverTheSpotConversionWidget ocw;
+TextCanvas *canvas;
+int attr;
+Position *leftp;
+Position *rightp;
+{
+    int nsegs = ocw->overthespot.numsegments;
+    DisplaySegment *dseg = ocw->overthespot.dispsegments;
+    DisplayFragment *dfp;
+    Position left, right;
+
+    left = 32767;
+    right = 0;
+
+    while (nsegs-- > 0) {
+	if (dseg->seg.attr & attr) {
+	    dfp = dseg->fragments;
+
+	    while (dfp != NULL) {
+		if (dfp->canvas == canvas) {
+		    if (dfp->region.x < left) left = dfp->region.x;
+		    if (right < dfp->region.x + dfp->region.width) {
+			right = dfp->region.x + dfp->region.width;
+		    }
+		}
+		dfp = dfp->next;
+	    }
+	}
+	dseg++;
+    }
+
+    if (left > right) return False;
+
+    *leftp = left + canvas->x;
+    *rightp = right + canvas->x;
+    return True;
+}
+
+/*- getInsertingSegmentRange: compute span of segments which has insert cursor -*/
+static Boolean
+getInsertingSegmentRange(ocw, canvas, curseg, offset, leftp, rightp, posp)
+OverTheSpotConversionWidget ocw;
+TextCanvas *canvas;
+Cardinal curseg;
+Cardinal offset;
+Position *leftp;
+Position *rightp;
+Position *posp;
+{
+    DisplaySegment *dseg = ocw->overthespot.dispsegments + curseg;
+    DisplayFragment *dfp;
+    Position left, right, insert;
+
+    left = 32767;
+    right = 0;
+
+    dfp = dseg->fragments;
+
+    while (dfp != NULL) {
+	if (dfp->canvas == canvas &&
+	    dfp->from <= offset && offset <= dfp->from + dfp->nchars) {
+	    if (dfp->region.x < left) left = dfp->region.x;
+	    if (right < dfp->region.x + dfp->region.width) {
+		right = dfp->region.x + dfp->region.width;
+	    }
+
+	    if (offset == dfp->from) {
+		insert = dfp->region.x;
+	    } else if (offset == dfp->from + dfp->nchars) {
+		insert = dfp->region.x + dfp->region.width;
+	    } else {
+		insert = dfp->region.x +
+		         CDStringWidth(ocw->overthespot.displayobj,
+				       &dseg->seg, dfp->from,
+				       offset);
+	    }
+	    break;
+	}
+	dfp = dfp->next;
+    }
+
+    if (left > right) return False;
+
+    *leftp = left + canvas->x;
+    *rightp = right + canvas->x;
+    *posp = insert + canvas->x;
+    return True;
+}
+
+/*- adjustOffset: make the span fit within the specified area -*/
+static void
+adjustOffset(rectp, left, right, offsetp, force)
+XRectangle *rectp;
+Position left;
+Position right;
+Position *offsetp;
+Boolean force;
+{
+    Position offset = *offsetp;
+
+    if (rectp->x <= left + offset &&
+	right + offset <= rectp->x + rectp->width) return;
+
+    if (right - left > rectp->width) {
+	if (!force) return;
+	/* centering */
+	offset = (rectp->x + rectp->width / 2) - (right + left) / 2;
+    } else {
+	if (left + offset < rectp->x) {
+	    offset = rectp->x - left;
+	} else if (rectp->x + rectp->width < right + offset) {
+	    offset = rectp->x + rectp->width - right;
+	}
+    }
+    *offsetp = offset;
+    return;
+}
+
+
+/*
+ *+ insert cursor handling functions
+ */
+
+/*- eraseCursor: erase insert cursor -*/
+static void
+eraseCursor(ocw)
+OverTheSpotConversionWidget ocw;
+{
+    if (!ocw->overthespot.cursorvisible) return;
+
+    TRACE(("eraseCursor() at (%d,%d)\n",
+	    ocw->overthespot.cursorlocation.x,
+	    ocw->overthespot.cursorlocation.y));
+    CDDrawCursor(ocw->overthespot.displayobj,
+		 ocw->overthespot.cursorlocation.canvas->canvas,
+		 ocw->overthespot.cursorlocation.x,
+		 ocw->overthespot.cursorlocation.y,
+		 False);
+    ocw->overthespot.cursorvisible = False;
+}
+
+/*- showCursor: draw insert cursor -*/
+static void
+showCursor(ocw)
+OverTheSpotConversionWidget ocw;
+{
+    if (!ocw->overthespot.cursorvisible) return;
+
+    TRACE(("showCursor at (%d,%d)\n",
+	    ocw->overthespot.cursorlocation.x,
+	    ocw->overthespot.cursorlocation.y));
+    CDDrawCursor(ocw->overthespot.displayobj,
+		 ocw->overthespot.cursorlocation.canvas->canvas,
+		 ocw->overthespot.cursorlocation.x,
+		 ocw->overthespot.cursorlocation.y,
+		 True);
+}
+
+/*- exposeCursor: make the insert cursor redraw correctly when exposing -*/
+static Boolean
+exposeCursor(ocw, w, region)
+OverTheSpotConversionWidget ocw;
+Widget w;
+XRectangle *region;
+{
+    XRectangle bounds;
+
+    if (!ocw->overthespot.cursorvisible ||
+	w != ocw->overthespot.cursorlocation.canvas->canvas) return False;
+
+    TRACE(("exposeCursor(region=%d,%d-%d,%d)\n",
+	    region->x, region->y, region->width, region->height));
+    /*
+     * if a part of the insert cursor is in the exposing region,
+     * clear the entire cursor before redraw, since the cursor is
+     * drawn with xor mode.
+     */
+    CDGetCursorBounds(ocw->overthespot.displayobj, &bounds);
+    bounds.x += ocw->overthespot.cursorlocation.x;
+    bounds.y += ocw->overthespot.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->overthespot.cursorvisible = True;
+    return True;
+}
+
+/*- computeCursor: compute insert cursor position if visible -*/
+static void
+computeCursor(ocw)
+OverTheSpotConversionWidget ocw;
+{
+    DisplaySegment *dsp;
+    DisplayLocation disploc;
+    Cardinal seg, offset;
+
+    if (!ICCursorPos(ocw->ccontrol.inputobj, &seg, &offset)) {
+	ocw->overthespot.cursorvisible = False;
+	return;
+    }
+
+    /* sanity check */
+    if (seg >= ocw->overthespot.numsegments) return;
+    dsp = ocw->overthespot.dispsegments + seg;
+    if (offset > dsp->seg.nchars) return;
+
+    if (findLocation(ocw, dsp, offset, &disploc) == NULL) return;
+
+    disploc.y += ocw->overthespot.ascent;
+
+    ocw->overthespot.cursorvisible = True;
+    ocw->overthespot.cursorlocation = disploc;
+}
+
+/*
+ *+ resource converter
+ */
+
+/*- StringToModeLocation: string->mode-location resource converter -*/
+/* ARGSUSED */
+static void
+StringToModeLocation(args, num_args, from, to)
+XrmValue *args;
+Cardinal *num_args;
+XrmValue *from;
+XrmValue *to;
+{
+    char *s = (char *)from->addr;
+    static ModeLocation ml = ModeBottomLeft;
+
+    if (!XmuCompareISOLatin1(s, "topleft")) ml = ModeTopLeft;
+    else if (!XmuCompareISOLatin1(s, "topright")) ml = ModeTopRight;
+    else if (!XmuCompareISOLatin1(s, "bottomleft")) ml = ModeBottomLeft;
+    else if (!XmuCompareISOLatin1(s, "bottomright")) ml = ModeBottomRight;
+    else if (!XmuCompareISOLatin1(s, "tracktext")) ml = ModeTrackText;
+    else if (!XmuCompareISOLatin1(s, "none")) ml = ModeNone;
+    else {
+	XtStringConversionWarning(s, XtRModeLocation);
+    }
+
+    to->size = sizeof(ModeLocation);
+    to->addr = (caddr_t)&ml;
+}
+
+/*
+ *+ miscellaneous functions
+ */
+
+/*- MoveShell: move shell widget -*/
+static void
+MoveShell(w, x, y)
+Widget w;
+Position x;
+Position y;
+{
+    ShellWidget shell = (ShellWidget)w;
+
+    TRACE(("MoveShell(%s,x=%d,y=%d,core.x=%d,core.y=%d)\n",XtName(w),x,y,w->core.x,w->core.y));
+    XtCheckSubclass(w, shellWidgetClass,
+		    "MoveShell: specified widget is not a shell");
+    /*
+     * calling XtMoveWidget() is NOT enough to move shell widgets when
+     * they are not mapped. we must use XtMakeGeometryRequest() or
+     * XtSetValues() to invoke root-geometry-manager which modifies
+     * the size hint appropriately.
+     */
+    if (shell->shell.popped_up) {
+	XtMoveWidget(w, x, y);
+    } else {
+	XtWidgetGeometry req;
+
+	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, wm_state)
+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)
+     */
+    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 (w == NULL) return;
+    if (!XtIsRealized(w)) XtRealizeWidget(w);
+    XSetTransientForHint(XtDisplay(w), XtWindow(w), win);
+}
+
+/*-setMwmHints: set _MOTIF_WM_HINTS for mode shell -*/
+static void
+setMwmHints(w)
+Widget w;
+{
+#define MWM_HINTS_ATOM		"_MOTIF_WM_HINTS"
+#define MWM_HINTS_DECOR		(1 << 1)
+#define MWM_DECOR_BORDER	(1 << 1)
+    Atom mwm_hints;
+    unsigned long hints[5];
+
+    if (w == NULL) return;
+    if (!XtIsRealized(w)) XtRealizeWidget(w);
+
+    mwm_hints = CachedInternAtom(XtDisplay(w), MWM_HINTS_ATOM, False);
+    if (mwm_hints == None) return;	/* just in case.. */
+
+    hints[0] = MWM_HINTS_DECOR;		/* flags */
+    hints[2] = MWM_DECOR_BORDER;	/* decorations */
+    hints[1] = hints[3] = hints[4] = 0;	/* functions, input mode and status */
+
+    XChangeProperty(XtDisplay(w), XtWindow(w),
+		    mwm_hints, mwm_hints, 32, PropModeReplace,
+		    (unsigned char *)hints, 5);
+}
+
+/*- getFocusOffset: get the focus window's position relative to the client window -*/
+static void
+getFocusOffset(ocw)
+OverTheSpotConversionWidget ocw;
+{
+    int offx, offy;
+    Window junkw;
+
+    if (ocw->ccontrol.focuswindow == ocw->ccontrol.clientwindow) {
+	FOCUSOFFX(ocw) = 0;
+	FOCUSOFFY(ocw) = 0;
+	return;
+    }
+    XTranslateCoordinates(XtDisplay((Widget)ocw),
+			  ocw->ccontrol.focuswindow,
+			  ocw->ccontrol.clientwindow,
+			  0, 0, &offx, &offy, &junkw);
+    FOCUSOFFX(ocw) = offx;
+    FOCUSOFFY(ocw) = offy;
+}
+   
+/*- intersectRect: returns given 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 minimum rectangle that covers given 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;
+}
+
+/*- enoughSpaceForStatus: checks if there's enough space for the status display -*/
+static int
+enoughSpaceForStatus(ocw)
+OverTheSpotConversionWidget ocw;
+{
+    Widget modew = ocw->overthespot.modewidget_fix;
+    int modespace;
+    int ascent = ocw->overthespot.ascent;
+    int descent = ocw->overthespot.lineheight - ascent;
+    int lspace = ocw->overthespot.linespacing;
+    int areatop = CLAREA(ocw).y;
+    int areabottom = CLAREA(ocw).y + CLAREA(ocw).height;
+    int top, bottom, y;
+
+    if (lspace == 0) lspace = 1;	/* avoid "divide by zero" error */
+
+    /*
+     * tracking $B%9%F!<%?%9$,I=<($G$-$k$+$I$&$+%A%'%C%/$9$k$K$O!"%/%i%$(B
+     * $B%"%s%H%(%j%"$KI=<($G$-$k:G=i$H:G8e$N9T$K$D$$$F$=$N>e$+2<$K%9%F!<(B
+     * $B%?%9$,I=<($G$-$k$3$H$rD4$Y$l$P$h$$!#(B
+     */
+
+    modespace = modew->core.height + modew->core.border_width * 2 + 2;
+
+    /* $B:G=i$N9T$N>e2<$N(B Y $B:BI8$r7W;;$7$F%9%F!<%?%9$,I=<($G$-$k$+D4$Y$k(B */
+    y = SPOTY(ocw) - ascent;
+    top = y - ((y - areatop) / lspace) * lspace;
+    bottom = top + ascent + descent;
+    if (top - areatop < modespace && areabottom - bottom < modespace) {
+	return 0;
+    }
+
+    /* $B:G8e$N9T$N>e2<$N(B Y $B:BI8$r7W;;$7$F%9%F!<%?%9$,I=<($G$-$k$+D4$Y$k(B */
+    y = SPOTY(ocw) + descent;
+    bottom = y + ((areabottom - y) / lspace) * lspace;
+    top = bottom - (ascent + descent);
+    if (top - areatop < modespace && areabottom - bottom < modespace) {
+	return 0;
+    }
+
+    return 1;
+}
+
+static DisplayFragment *free_fragments = NULL;
+
+/*- allocDisplayFragment: get 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 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: 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)
+OverTheSpotConversionWidget ocw;
+int n;
+{
+    if (ocw->overthespot.dispsegmentsize > n) return;
+    n = ((n + 3) / 4) * 4 ;
+    if (ocw->overthespot.dispsegments == NULL) {
+	ocw->overthespot.dispsegments = (DisplaySegment *)XtMalloc(n * sizeof(DisplaySegment));
+    } else {
+	ocw->overthespot.dispsegments = (DisplaySegment *)XtRealloc((char *)ocw->overthespot.dispsegments, n * sizeof(DisplaySegment));
+    }
+    ocw->overthespot.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)
+OverTheSpotConversionWidget ocw;
+{
+    DisplaySegment *dsp = ocw->overthespot.dispsegments;
+    int i;
+
+    for (i = 0; i < ocw->overthespot.numsegments; i++) {
+	freeDisplaySegment(dsp++);
+    }
+    ocw->overthespot.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;
+}