/**
 *
 * $Header: /cvsroot/hungry/lesstif/lib/Xm-2.0/Text.c,v 1.11 1997/12/18 23:22:12 u27113 Exp $
 *
 * Copyright (C) 1997 Free Software Foundation, Inc.
 *
 * This file is part of the GNU LessTif Library.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the Free
 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 **/

static char rcsid[] = "$Header: /cvsroot/hungry/lesstif/lib/Xm-2.0/Text.c,v 1.11 1997/12/18 23:22:12 u27113 Exp $";

#undef VERBOSE

#include <LTconfig.h>
#include <Xm/XmP.h>
#include <Xm/TextP.h>
#include <Xm/TextOutP.h>
#include <Xm/TextF.h>

#include <Xm/TransltnsP.h>
#include <Xm/ScrolledW.h>
#include <XmI/XmI.h>
#include <X11/Xfuncs.h>

#include <limits.h>		/* for INT_MAX */
#ifdef HAVE_STRING_H
#include <string.h>
#define ANSI_STRING
#else
#include <strings.h>
#endif
#include <stdlib.h>
#include <XmI/DebugUtil.h>

#ifndef XmUNSPECIFIED
#define XmUNSPECIFIED (~0)
#endif

#define _XmMin(a,b)  ((a) < (b)) ? (a) : (b)
#define _XmMax(a,b)  ((a) > (b)) ? (a) : (b)

/* Forward Declarations */

static void ClassInitialize();

static void ClassPartInitialize(WidgetClass class);

static void Initialize(Widget request, Widget new,
		       ArgList args, Cardinal *num_args);

static void Destroy(Widget w);

static void Resize(Widget w);

static void Realize(Widget w, XtValueMask *value_mask,
		    XSetWindowAttributes *attributes);

static void DoExpose(Widget w, XEvent *event, Region region);

static XtGeometryResult QueryGeometry(Widget w,
				      XtWidgetGeometry *proposed,
				      XtWidgetGeometry *answer);

static void _XmTextSetEditable(Widget w, Boolean e);

static Boolean SetValues(Widget current, Widget request, Widget new,
			 ArgList args, Cardinal *num_args);

static void RefigureLines(XmTextWidget w);

static void InitializeLineTable(XmTextWidget w);

static Cardinal GetSecResData(WidgetClass wc,
			      XmSecondaryResourceData **resdata);

static OutputCreateProc output_create = _XmTextOutputCreate;

static InputCreateProc input_create = _XmTextInputCreate;

void _XmTextInvalidate(XmTextWidget w, XmTextPosition position,
		       XmTextPosition topos, long delta);

void _XmTextExportValue(Widget w, int offset, XtArgVal *value);

void TextGetValues(Widget w, ArgList args, Cardinal *num_args);

void _XmChangeVSB(XmTextWidget w, XmTextPosition pos);

/* 2.0 */
#include <Xm/TraitP.h>
#include <Xm/AccTextT.h>
static XtPointer _XmText_TraitGetValue(Widget w, int format);
static void _XmText_TraitSetValue(Widget w, XtPointer value, int format);
static int _XmText_TraitPreferredFormat(Widget w);

/* Trait record */
XmAccessTextualTraitRec _XmTextTraitRec =
	{	/* version */		0,
		/* getValue */		_XmText_TraitGetValue,
		/* setValue */		_XmText_TraitSetValue,
		/* preferredFormat */	_XmText_TraitPreferredFormat,
	};

#define Offset(_name) XtOffsetOf(XmTextRec, text._name)

/* Resources for the Text  class */
static XtResource resources[] =
{
    {
	XmNsource, XmCSource, XmRPointer,
	sizeof(XmTextSource), Offset(source),
	XmRPointer, (XtPointer)NULL
    },
    {
	XmNactivateCallback, XmCCallback, XmRCallback,
	sizeof(XtCallbackList), Offset(activate_callback),
	XmRCallback, (XtPointer)NULL
    },
    {
	XmNfocusCallback, XmCCallback, XmRCallback,
	sizeof(XtCallbackList), Offset(focus_callback),
	XmRCallback, (XtPointer)NULL
    },
    {
	XmNlosingFocusCallback, XmCCallback, XmRCallback,
	sizeof(XtCallbackList), Offset(losing_focus_callback),
	XmRCallback, (XtPointer)NULL
    },
    {
	XmNvalueChangedCallback, XmCCallback, XmRCallback,
	sizeof(XtCallbackList), Offset(value_changed_callback),
	XmRCallback, (XtPointer)NULL
    },
    {
	XmNmodifyVerifyCallback, XmCCallback, XmRCallback,
	sizeof(XtCallbackList), Offset(modify_verify_callback),
	XmRCallback, (XtPointer)NULL
    },
    {
	XmNmodifyVerifyCallbackWcs, XmCCallback, XmRCallback,
	sizeof(XtCallbackList), Offset(wcs_modify_verify_callback),
	XmRCallback, (XtPointer)NULL
    },
    {
	XmNmotionVerifyCallback, XmCCallback, XmRCallback,
	sizeof(XtCallbackList), Offset(motion_verify_callback),
	XmRCallback, (XtPointer)NULL
    },
    {
	XmNgainPrimaryCallback, XmCCallback, XmRCallback,
	sizeof(XtCallbackList), Offset(gain_primary_callback),
	XmRCallback, (XtPointer)NULL
    },
    {
	XmNlosePrimaryCallback, XmCCallback, XmRCallback,
	sizeof(XtCallbackList), Offset(lose_primary_callback),
	XmRCallback, (XtPointer)NULL
    },
    {
	XmNvalue, XmCValue, XmRString,
	sizeof(String), Offset(value),
	XmRString, (XtPointer)NULL
    },
    {
	XmNvalueWcs, XmCValueWcs, XmRValueWcs,
	sizeof(wchar_t *), Offset(wc_value),
	XmRString, (XtPointer)NULL
    },
    {
	XmNmaxLength, XmCMaxLength, XmRInt,
	sizeof(int), Offset(max_length),
	XmRImmediate, (XtPointer)INT_MAX
    },
    {
	XmNmarginHeight, XmCMarginHeight, XmRVerticalDimension,
	sizeof(Dimension), Offset(margin_height),
	XmRImmediate, (XtPointer)5
    },
    {
	XmNmarginWidth, XmCMarginWidth, XmRHorizontalDimension,
	sizeof(Dimension), Offset(margin_width),
	XmRImmediate, (XtPointer)5
    },
    {
	XmNoutputCreate, XmCOutputCreate, XmRFunction,
	sizeof(OutputCreateProc), Offset(output_create),
	XmRFunction, (XtPointer)&output_create
    },
    {
	XmNinputCreate, XmCInputCreate, XmRFunction,
	sizeof(InputCreateProc), Offset(input_create),
	XmRFunction, (XtPointer)&input_create
    },
    {
	XmNtopCharacter, XmCTopCharacter, XmRTextPosition,
	sizeof(XmTextPosition), Offset(top_character),
	XmRImmediate, (XtPointer)0
    },
    {
	XmNcursorPosition, XmCCursorPosition, XmRTextPosition,
	sizeof(XmTextPosition), Offset(cursor_position),
	XmRImmediate, (XtPointer)0
    },
    {
	XmNeditMode, XmCEditMode, XmREditMode,
	sizeof(int), Offset(edit_mode),
	XmRImmediate, (XtPointer)XmSINGLE_LINE_EDIT
    },
    {
	XmNautoShowCursorPosition, XmCAutoShowCursorPosition, XmRBoolean,
	sizeof(Boolean), Offset(auto_show_cursor_position),
	XmRImmediate, (XtPointer)True
    },
    {
	XmNeditable, XmCEditable, XmRBoolean,
	sizeof(Boolean), Offset(editable),
	XmRImmediate, (XtPointer)True
    },
    {
	XmNverifyBell, XmCVerifyBell, XmRBoolean,
	sizeof(Boolean), Offset(verify_bell),
	XtRImmediate, (XtPointer)((unsigned char)XmUNSPECIFIED)
    },
    {
	XmNnavigationType, XmCNavigationType, XmRNavigationType,
    sizeof(XmNavigationType), XtOffsetOf(XmTextRec, primitive.navigation_type),
	XmRImmediate, (XtPointer)XmTAB_GROUP
    }
};

static XmSyntheticResource syn_resources[] =
{
    {
	XmNmarginWidth,
	sizeof(Dimension), Offset(margin_width),
	_XmFromHorizontalPixels, _XmToHorizontalPixels
    },
    {
	XmNmarginHeight,
	sizeof(Dimension), Offset(margin_height),
	_XmFromVerticalPixels, _XmToVerticalPixels
    },
    {
	XmNvalue,
	sizeof(String), Offset(value),
	_XmTextExportValue, NULL
    }
};
#undef Offset

char _XmText_EventBindings1[] =
"<Key>F2:    backward-word()\n" \
"<Key>F3:    backward-paragraph()\n" \
"<Key>F4:    beginning-of-line()\n" \
"<Key>F5:    forward-word()\n" \
"<Key>F6:    forward-paragraph()\n" \
"<Key>F7:	end-of-line()\n" \
"Ctrl<Key>5:    forward-paragraph()\n" \
"Ctrl<Key>A:    beginning-of-line()\n" \
"Ctrl<Key>B:    backward-character()\n" \
"Ctrl<Key>C:    paste-clipboard()\n" \
"Ctrl<Key>D:    delete-next-character()\n" \
"Ctrl<Key>E:	end-of-line()\n" \
"Ctrl<Key>F:    forward-character()\n" \
"Ctrl<Key>H:    delete-previous-character()\n" \
"Ctrl<Key>J:	newline-and-indent()\n" \
"Ctrl<Key>K:    kill-to-end-of-line()\n" \
"Ctrl<Key>L:    redraw-display()\n" \
"Ctrl<Key>M:	newline()\n" \
"Ctrl<Key>N:	next-line()\n" \
"Ctrl<Key>O:	newline-and-backup()\n" \
"Ctrl<Key>P:	previous-line()\n" \
"Ctrl<Key>V:	next-page()\n" \
"Ctrl<Key>W:    kill-selection()\n" \
"Meta<Key>B:    backward-word()\n" \
"Meta<Key>F:    forward-word()\n" \
"Meta<Key>V:    previous-page()\n" \
":Meta<Key>d:	delete-next-word()\n" \
":Meta<Key>h:	delete-previous-word()\n" \
":m <Key>osfPrimaryPaste: cut-primary()\n\
:a <Key>osfPrimaryPaste: cut-primary()\n\
:<Key>osfPrimaryPaste:	copy-primary()\n\
:m <Key>osfCut:		cut-primary()\n\
:a <Key>osfCut:		cut-primary()\n\
:<Key>osfCut:		cut-clipboard()\n\
:<Key>osfPaste:		paste-clipboard()\n\
:m <Key>osfCopy:	copy-primary()\n\
:a <Key>osfCopy:	copy-primary()\n\
:<Key>osfCopy:		copy-clipboard()\n\
s <Key>osfBeginLine:	beginning-of-line(extend)\n\
:<Key>osfBeginLine:	beginning-of-line()\n\
s <Key>osfEndLine:	end-of-line(extend)\n\
:<Key>osfEndLine:	end-of-line()\n\
s <Key>osfPageLeft:	page-left(extend)\n\
:<Key>osfPageLeft:	page-left()\n\
s c<Key>osfPageUp:	previous-page(extend)\n\
:c <Key>osfPageUp:	previous-page()\n\
s <Key>osfPageRight:	page-right(extend)\n\
:<Key>osfPageRight:	page-right()\n\
s c <Key>osfPageDown:	next-page(extend)\n\
:c <Key>osfPageDown:	next-page()\n\
:<Key>osfClear:		clear-selection()\n\
:<Key>osfBackSpace:	delete-previous-character()\n\
s m <Key>osfDelete:	cut-primary()\n\
s a <Key>osfDelete:	cut-primary()\n\
s <Key>osfDelete:	cut-clipboard()\n\
:c <Key>osfDelete:	delete-to-end-of-line()\n\
:<Key>osfDelete:	delete-next-character()";

char _XmText_EventBindings2[] =
":c m <Key>osfInsert:	copy-primary()\n\
:c a <Key>osfInsert:	copy-primary()\n\
s <Key>osfInsert:	paste-clipboard()\n\
:c <Key>osfInsert:	copy-clipboard()\n\
:s <Key>osfSelect:	key-select()\n\
:<Key>osfSelect:	set-anchor()\n\
:<Key>osfActivate:	activate()\n\
:<Key>osfAddMode:	toggle-add-mode()\n\
:<Key>osfHelp:		Help()\n\
:<Key>osfCancel:	process-cancel()\n\
s c <Key>osfLeft:	backward-word(extend)\n\
:c <Key>osfLeft:	backward-word()\n\
s <Key>osfLeft:		key-select(left)\n\
:<Key>osfLeft:		backward-character()\n\
s c <Key>osfRight:	forward-word(extend)\n\
:c <Key>osfRight:	forward-word()\n\
s <Key>osfRight:	key-select(right)\n\
:<Key>osfRight:		forward-character()\n\
:<Key>osfUp:		previous-line()\n\
:<Key>osfDown:		next-line()\n\
c ~m ~a <Key>slash:	select-all()\n\
c ~m ~a <Key>backslash:	deselect-all()\n\
s ~m ~a <Key>Tab:	prev-tab-group()\n\
~m ~a <Key>Tab:		next-tab-group()\n\
~s ~m ~a <Key>Return:	newline()\n\
c ~s ~m ~a <Key>space:	set-anchor()\n\
c s ~m ~a <Key>space:	key-select()\n\
s ~c ~m ~a <Key>space:	self-insert()\n\
<Key>:			self-insert()";

char _XmText_EventBindings3[] =
"<Unmap>:		unmap()\n\
<Enter>:		enter-window()\n\
<Leave>:		leave-window()\n\
<FocusIn>:		focus-in()\n\
<FocusOut>:		focus-out()\n\
~c s ~m ~a <Btn1Down>:	extend-start()\n\
c ~s ~m ~a <Btn1Down>:	move-destination()\n\
~c ~s ~m ~a <Btn1Down>:	grab-focus()\n\
~c ~m ~a <Btn1Motion>:	extend-adjust()\n\
~c ~m ~a <Btn1Up>:	extend-end()\n\
<Btn2Down>:		process-bdrag()\n\
m ~a <Btn2Motion>:	secondary-adjust()\n\
~m a <Btn2Motion>:	secondary-adjust()\n\
~s <Btn2Up>:		copy-to()\n\
~c <Btn2Up>:		move-to()";

/* *INDENT-OFF* */
static XmBaseClassExtRec textBaseClassExtRec = {
    /* next_extension            */ NULL,
    /* record_type               */ NULLQUARK,                             
    /* version                   */ XmBaseClassExtVersion,
    /* size                      */ sizeof(XmBaseClassExtRec),
    /* initialize_prehook        */ XmInheritInitializePrehook,
    /* set_values_prehook        */ XmInheritSetValuesPrehook, 
    /* initialize_posthook       */ XmInheritInitializePosthook,
    /* set_values_posthook       */ XmInheritSetValuesPosthook,
    /* secondary_object_class    */ NULL, /* FIX ME */
    /* secondary_object_create   */ XmInheritSecObjectCreate,
    /* get_secondary_resources   */ GetSecResData,
    /* fast_subclass             */ { 0 },
    /* get_values_prehook        */ XmInheritGetValuesPrehook,
    /* get_values_posthook       */ XmInheritGetValuesPosthook,
    /* class_part_init_prehook   */ XmInheritClassPartInitPrehook,
    /* class_part_init_posthook  */ XmInheritClassPartInitPosthook,
    /* ext_resources             */ NULL,
    /* compiled_ext_resources    */ NULL,
    /* num_ext_resources         */ 0,
    /* use_sub_resources         */ False,
    /* widget_navigable          */ XmInheritWidgetNavigable,
    /* focus_change              */ XmInheritFocusChange,
    /* wrapper_data              */ NULL
};

XmPrimitiveClassExtRec _XmTextPrimClassExtRec =
{
    /* next_extension      */ NULL,
    /* record_type         */ NULLQUARK,
    /* version             */ XmPrimitiveClassExtVersion,
    /* record_size         */ sizeof(XmPrimitiveClassExtRec),
    /* widget_baseline     */ _XmTextGetBaselines,
    /* widget_display_rect */ _XmTextGetDisplayRect,
    /* widget_margins      */ _XmTextMarginsProc
};

XmTextClassRec xmTextClassRec =
{
    /* Core class part */
  {
	/* superclass            */ (WidgetClass) & xmPrimitiveClassRec,
	/* class_name            */ "XmText",
	/* widget_size           */ sizeof(XmTextRec),
	/* class_initialize      */ ClassInitialize,
	/* class_part_initialize */ ClassPartInitialize,
	/* class_inited          */ False,
	/* initialize            */ Initialize,
	/* initialize_hook       */ NULL,
	/* realize               */ Realize,
	/* actions               */ NULL, /* set in ClassInitialize */
	/* num_actions           */ 0, /* set in ClassInitialize */
	/* resources             */ resources,
	/* num_resources         */ XtNumber(resources),
	/* xrm_class             */ NULLQUARK,
	/* compress_motion       */ True,
	/* compress_exposure     */ XtExposeCompressMaximal,
	/* compress_enterleave   */ True,
	/* visible_interest      */ False,
	/* destroy               */ Destroy,
	/* resize                */ Resize,
	/* expose                */ DoExpose,
	/* set_values            */ SetValues,
	/* set_values_hook       */ NULL,
	/* set_values_almost     */ XtInheritSetValuesAlmost,
	/* get_values_hook       */ TextGetValues,
	/* accept_focus          */ NULL,
	/* version               */ XtVersion,
	/* callback offsets      */ NULL,
	/* tm_table              */ NULL,
	/* query_geometry        */ QueryGeometry,
	/* display_accelerator   */ XtInheritDisplayAccelerator,
	/* extension             */ (XtPointer) & textBaseClassExtRec
  },
    /* Primitive Class part */
  {
	/* border_highlight      */ XmInheritBorderHighlight,
	/* border_unhighlight    */ XmInheritBorderUnhighlight,
	/* translations          */ NULL,
	/* arm_and_activate_proc */ XmInheritArmAndActivate,
	/* synthetic resources   */ syn_resources,
	/* num syn res           */ XtNumber(syn_resources),
	/* extension             */ (XtPointer) & _XmTextPrimClassExtRec,
  },
    /* Text Class part */
  {
	/* extension */ NULL
  }
};
/* *INDENT-ON* */

WidgetClass xmTextWidgetClass = (WidgetClass)&xmTextClassRec;



/* Inner Widget--------------------------------------------------------------
 * the base for the Output and Input objects
 */
/*
 * Is this function ever used ?
 */
static void
InnerInitialize(Widget request, Widget new_w, ArgList args, Cardinal *num_args)
{
	DEBUGOUT(XdbDebug(__FILE__, new_w,
		"InnerInitialize: %i args\n"
		"\trequest X %5i Y %5i W %5i H %5i\n"
		"\t  new_w X %5i Y %5i W %5i H %5i\n",
		*num_args,
		XtX(request), XtY(request),
		XtWidth(request), XtHeight(request),
		XtX(new_w), XtY(new_w),
		XtWidth(new_w), XtHeight(new_w)));
	DEBUGOUT(XdbPrintArgList(__FILE__, new_w, args, *num_args, False));
}

/*
 * Is this function ever used ?
 */
static void
InnerDestroy(Widget w)
{
    /* Destroy Output and Input */
    /* Nah - already done in XmText's destroy method (Destroy). */
}

/*
 * Is this function ever used ?
 */
static Boolean
InnerSetValues(Widget old, Widget request, Widget new_w,
	       ArgList args, Cardinal *num_args)
{
	Boolean refresh_needed = False;

	DEBUGOUT(XdbDebug(__FILE__, new_w,
		"InnerSetValues: %i args\n"
		"\t    old X %5i Y %5i W %5i H %5i\n"
		"\trequest X %5i Y %5i W %5i H %5i\n"
		"\t  new_w X %5i Y %5i W %5i H %5i\n",
		*num_args,
		XtX(old), XtY(old),
		XtWidth(old), XtHeight(old),
		XtX(request), XtY(request),
		XtWidth(request), XtHeight(request),
		XtX(new_w), XtY(new_w),
		XtWidth(new_w), XtHeight(new_w)));
	DEBUGOUT(XdbPrintArgList(__FILE__, new_w, args, *num_args, False));

	return refresh_needed;
}

XmTextInnerClassRec xmTextInnerClassRec =
{
    /* core_class fields */
    {
    /* superclass               */ (WidgetClass)(&objectClassRec),
    /* class_name               */ "XmTextInner",
    /* widget_size              */ sizeof(XmTextInnerRec),
    /* class_initialize         */ NULL,
    /* class_part_initialize    */ NULL,
    /* class_inited             */ False,
    /* initialize               */ InnerInitialize,
    /* initialize_hook          */ NULL,
    /* obj1                     */ NULL,
    /* obj2                     */ NULL,
    /* obj3                     */ 0,
    /* resources                */ NULL,
    /* num_resources            */ 0,
    /* xrm_class                */ NULLQUARK,
    /* obj4                     */ False,
    /* obj5                     */ False,
    /* obj6                     */ False,
    /* obj7                     */ False,
    /* destroy                  */ InnerDestroy,
    /* obj8                     */ NULL,
    /* obj9                     */ NULL,
    /* set_values               */ InnerSetValues,
    /* set_values_hook          */ NULL,
    /* obj10                    */ NULL,
    /* get_values_hook          */ NULL,
    /* obj11                    */ NULL,
    /* version                  */ XtVersion,
    /* callback_private         */ NULL,
    /* obj12                    */ NULL,
    /* obj13                    */ NULL,
    /* obj14                    */ NULL,
    /* extension                */ NULL
    },
    /* TextInner Class part */
    {
	/* extension */ NULL
    }
};

WidgetClass xmTextInnerObjectClass = (WidgetClass)&xmTextInnerClassRec;


/* Text-----------------------------------------------------------------------

 * Widget methods
 */



extern Boolean _XmCvtStringToXmString(Display *, XrmValue *, Cardinal *,
				      XrmValue *, XrmValue *, XtPointer *);

extern XmFontList _XmFontListCreateDefault(Display *);

static void
ClassInitialize()
{
    int len1 = strlen(_XmTextIn_XmTextEventBindings1);
    int len2 = strlen(_XmTextIn_XmTextEventBindings2);
    int len3 = strlen(_XmTextIn_XmTextEventBindings3);
    char *buf = XtMalloc((unsigned)(len1 + len2 + len3 + 1));
    char *cp = buf;

    DEBUGOUT(XdbDebug(__FILE__, NULL, "XmText ClassInitialize\n"));

    textBaseClassExtRec.record_type = XmQmotif;
    xmTextClassRec.core_class.actions =
	(XtActionsRec *)_XmdefaultTextActionsTable;

    xmTextClassRec.core_class.num_actions = _XmdefaultTextActionsTableSize;

    (void)strcpy(cp, _XmTextIn_XmTextEventBindings1);
    cp += len1;

    (void)strcpy(cp, _XmTextIn_XmTextEventBindings2);
    cp += len2;

    (void)strcpy(cp, _XmTextIn_XmTextEventBindings3);

    xmTextClassRec.core_class.tm_table = buf;

    if (!XmeTraitSet(xmTextWidgetClass, XmQTaccessTextual, &_XmTextTraitRec)) {
	DEBUGOUT(XdbDebug(__FILE__, NULL,
		"ClassInitialize: XmeTraitSet failed\n"));
    }
}

static void
ClassPartInitialize(WidgetClass widget_class)
{
    DEBUGOUT(XdbDebug(__FILE__, NULL, "XmText ClassPartInitialize\n"));

    _XmFastSubclassInit(widget_class, XmTEXT_BIT);
}

static void
Initialize(Widget request, Widget new,
	   ArgList args, Cardinal *num_args)
{
    XmTextWidget w = (XmTextWidget)new;

    DEBUGOUT(XdbDebug(__FILE__, new,
	"initialize: %i args\n"
	"\trequest X %5i Y %5i W %5i H %5i\n"
	"\t  new   X %5i Y %5i W %5i H %5i\n",
	*num_args,
	XtX(request), XtY(request),
	XtWidth(request), XtHeight(request),
	XtX(new), XtY(new),
	XtWidth(new), XtHeight(new)));
    DEBUGOUT(XdbPrintArgList(__FILE__, new, args, *num_args, False));


    if (XtWidth(request) == 0)
    {
	XtWidth(new) = 0;
    }
    if (XtHeight(request) == 0)
    {
	XtHeight(new) = 0;
    }

#if 0
    XtAugmentTranslations((Widget)w,
			  XtParseTranslationTable(_XmText_EventBindings2));

    XtAugmentTranslations((Widget)w,
			  XtParseTranslationTable(_XmText_EventBindings3));
#endif

    w->text.inner_widget = XtCreateWidget("inner", xmTextInnerObjectClass,
					  new, args, *num_args);

    /* initialize the inner to sane values before fetching resources */
    bzero((char *)(w->text.inner_widget) + XtOffsetOf(XmTextInnerRec, inner),
	  sizeof(XmTextInnerPart));

    Text_TableSize(w) = Text_TotalLines(w) = 0;
    Text_LineTable(w) = NULL;
    Text_Line(w) = NULL;
    Text_LineMax(w) = Text_LineCount(w) = 0;
    Text_DisableDepth(w) = 0;
    Text_FirstPos(w) = Text_LastPos(w) = Text_TopPos(w) = Text_CursorPos(w) = 0;

    (*Text_OutputCreate(w)) ((Widget)w, args, *num_args);

    (*Text_InputCreate(w)) ((Widget)w, args, *num_args);

    InitializeLineTable(w);

    /* Highlight array */
    Text_Highlight(w).list = (_XmHighlightRec *)XtCalloc(32,
						      sizeof(_XmHighlightRec));
    Text_Highlight(w).maximum = 32;
    Text_Highlight(w).number = 0;
}

static void
Destroy(Widget w)
{
    DEBUGOUT(XdbDebug(__FILE__, w, "Destroy\n"));

    (*Text_Output(w)->destroy) (w);

    (*Text_Input(w)->destroy) (w);

    XtFree((XtPointer)Text_Highlight(w).list);
}

static Boolean
SetValues(Widget old, Widget request, Widget new,
	  ArgList args, Cardinal *num_args)
{
    Boolean refresh_needed = False;
    XmTextWidget nw = (XmTextWidget)new;
    XmTextWidget ow = (XmTextWidget)old;

    DEBUGOUT(XdbDebug(__FILE__, new,
	"set_values: %i args\n"
	"\t    old X %5i Y %5i W %5i H %5i\n"
	"\trequest X %5i Y %5i W %5i H %5i\n"
	"\t  new   X %5i Y %5i W %5i H %5i\n",
	*num_args,
	XtX(old), XtY(old),
	XtWidth(old), XtHeight(old),
	XtX(request), XtY(request),
	XtWidth(request), XtHeight(request),
	XtX(new), XtY(new),
	XtWidth(new), XtHeight(new)));
    DEBUGOUT(XdbPrintArgList(__FILE__, new, args, *num_args, False));

    if (Text_Value(nw) != Text_Value(ow))
    {
	XmTextSetString(new, Text_Value(new));

	refresh_needed = True;
    }

    if (Text_WcsValue(nw) != Text_WcsValue(ow))
    {
	XmTextSetStringWcs(new, Text_WcsValue(new));

	refresh_needed = True;
    }

    if (Text_Editable(nw) != Text_Editable(ow))
    {
	_XmTextSetEditable(new, Text_Editable(nw));

	refresh_needed = True;
    }

    /* Stuff that (hopefully) requires no further treatment,
     * but does require redisplay */
    if (Text_EditMode(nw) != Text_EditMode(ow) ||
	Text_AutoShowCursorPosition(nw) != Text_AutoShowCursorPosition(ow))
    {
	refresh_needed = True;
    }

    /* Call the SetValues in the input/output objects */
    (*Text_Input(new)->SetValues) (old, request, new, args, num_args);

    if ((*Text_Output(new)->SetValues) (old, request, new, args, num_args))
    {
	refresh_needed = True;
    }

    /* FIX ME - lots more cases */
    /*
     * From include/Xm/TextP.h :
     * XmTextSource source
     * XtCallbackList activate_callback, focus_callback, losing_focus_callback,
     *    value_changed_callback, modify_verify_callback,
     *    wcs_modify_verify_callback, motion_verify_callback,
     *    gain_primary_callback, lose_primary_callback
     * Dimension margin_height, margin_width, cursor_position_x
     * OutputCreateProc output_create
     * InputCreateProc input_create;
     *
     * XmTextPosition top_character;
     * XmTextPosition bottom_position;
     * XmTextPosition cursor_position;
     * int max_length;
     * Boolean add_mode;
     * Boolean traversed;
     * Boolean highlight_changed;
     * Boolean pendingoff;
     * char char_size;
     * OnOrOff on_or_off;
     * Output output;
     * Input input;
     * XmTextPosition first_position;
     * XmTextPosition last_position;
     * XmTextPosition forget_past;
     * XmTextPosition force_display;
     * XmTextPosition new_top;
     * XmTextPosition last_top_char;
     * XmTextPosition dest_position;
     * int disable_depth;
     * int pending_scroll;
     * int total_lines;
     * int top_line;
     * int vsbar_scrolling;
     * Cardinal number_lines;
     * Cardinal maximum_lines;
     * Line line;
     * Widget inner_widget;
     * XmTextLineTable line_table;
     * unsigned int table_size;
     * unsigned int table_index;
     */

    return refresh_needed;
}

static void
Realize(Widget aw, XtValueMask *value_mask, XSetWindowAttributes *attributes)
{
    XmTextWidget w = (XmTextWidget)aw;

    DEBUGOUT(XdbDebug(__FILE__, aw, "Realize\n"));

#define superclass (&xmPrimitiveClassRec)
    (*superclass->core_class.realize) (aw, value_mask, attributes);
#undef superclass

    RefigureLines(w);

    (*Text_Output(w)->realize) (aw, value_mask, attributes);

    _XmTextSetEditable(aw, Text_Editable(w));

    XmTextShowPosition(aw, Text_CursorPos(w));
}


static void
DoExpose(Widget aw, XEvent *event, Region region)
{
    XmTextWidget w = (XmTextWidget)aw;

    DEBUGOUT(XdbDebug(__FILE__, aw, "DoExpose\n"));

    if (Text_DisableDepth(w) != 0)
	return;		/* Should we be doing this ? FIX ME */

    if (!XtIsRealized(w))
    {
	return;
    }

    if (Text_NeedsRefigureLines(w))
    {
	RefigureLines(w);
    }

    (*Text_Output(w)->expose) (aw, event, region);
}

static void
Resize(Widget aw)
{
    XmTextWidget w = (XmTextWidget)aw;

    DEBUGOUT(XdbDebug(__FILE__, aw, "resize"));

    /* Resize can get called from XmScrolledWindowSetAreas before we actually
     * made it through our initialize method.  Make sure not to die because
     * of this
     */
    if (Text_Input(w) == NULL || Text_Output(w) == NULL)
    {
	return;
    }

    (*Text_Output(w)->resize) (aw, True);

    RefigureLines(w);
}

static XtGeometryResult
QueryGeometry(Widget w, XtWidgetGeometry *proposed, XtWidgetGeometry *answer)
{
    XmTextWidget tw = (XmTextWidget)w;
    XtWidgetGeometry a;

#define Wants(x)   (proposed->request_mode & x)
    DEBUGOUT(XdbDebug(__FILE__, w,
		      "QueryGeometry proposed width=%d height=%d mode=%X\n",
		   proposed->width, proposed->height, proposed->request_mode));

    if (proposed->request_mode != 0)
    {				/* NULL case should not yet end here ! */
	if ((!(Wants(CWWidth))) && (!Wants(CWHeight)))
	{
	    /* If they don't ask width/height, let them have what they like */
	    if (answer)
	    {
		*answer = *proposed;
	    }

	    return XtGeometryYes;
	}
    }

    a.request_mode = CWWidth | CWHeight;
    a.width = XtWidth(tw);
    a.height = XtHeight(tw);

    if (answer)
    {
	*answer = a;
    }

    /* NULL proposed -> return Width+Height */
    if (proposed->request_mode == 0)
    {
	return XtGeometryAlmost;
    }

    if (proposed->width >= answer->width && proposed->height >= answer->height)
    {
	return XtGeometryYes;
    }
    else if (answer->width == XtWidth(tw) && answer->height == XtHeight(tw))
    {
	if (answer)
	{
	    answer->request_mode = 0;
	}

	return XtGeometryNo;
    }
    else
    {
	return XtGeometryAlmost;
    }
}



/* Drawing Routines ------------------------------------------------------- */
static void
Redisplay(XmTextWidget w)
{
    DEBUGOUT(XdbDebug(__FILE__, (Widget)w, "Redisplay\n"));

    if (Text_DisableDepth(w) != 0)
	return;

    if (!XtIsRealized((Widget)w))
    {
	return;
    }

    Text_NeedsRedisplay(w) = False;

    if (Text_NeedsRefigureLines(w))
    {
	RefigureLines(w);
    }

    _XmChangeVSB(w, Text_TopPos(w));
    _XmRedisplayHBar(w, Out_XOffset(Text_OutputData(w)));

    (*Text_Output(w)->expose) ((Widget)w, NULL, NULL);
}

static
Cardinal
GetSecResData(WidgetClass wc, XmSecondaryResourceData **resdata)
{
    return 0;
}

/* Line Table Routines ---------------------------------------------------- */

static void
LineIncrease(XmTextWidget w, LineNum num)
{
    DEBUGOUT(XdbDebug(__FILE__, (Widget)w, "LineIncrease %d\n",num));

    if (num > Text_LineMax(w))
    {
	LineNum start = Text_LineMax(w);
	int i;

	Text_Line(w) = (Line)XtRealloc((char *)Text_Line(w),
				       sizeof(LineRec) * num);
	Text_LineMax(w) = num;

	for (i = start; i < num; i++)
	{
	    Line line = &Text_Line(w)[i];

	    line->extra = NULL;
	}
    }
}

/*
 * Set up the entire line table, starting with the first visible position.
 *
 * Note that there is 1 extra line in the table.  This is so we can find
 * out what the last position in any line is by looking at the first
 * position of the next line.  Oh, the limitations of Motif compatibility!
 */
/*
 * This new implementation of RefigureLines is necessary to implement
 * wrapping.
 * Inspection of the output of test/Xm/text/test6 reveals that Lines can
 * be built from the LineTable. As the LineTable has recently been reprogrammed
 * to contain wrapped lines, is seems logical to use that idea.
 * Some people will accuse me of NIH now :-)
 */
static void
RefigureLines(XmTextWidget w)
{
    XmTextPosition pos, next;
    int nlines, i;
    Line line = NULL;
    XmTextLineTable lte;
    LineTableExtra extra;
    Boolean more;

    DEBUGOUT(XdbDebug(__FILE__, (Widget)w, "RefigureLines\n"));

/*
 * DisableDepth is meant to optimize frequent updates to XmText.
 * This probably means we shouldn't do anything here ...
 *
 * Not too sure about this. FIX ME.
 */
    if (Text_DisableDepth(w) != 0)
	return;
/* End unsure stuff */

    Text_NeedsRefigureLines(w) = False;

    /* Too verbose to stay on ... */
#ifdef VERBOSE
    /* Show our input */
    for (i = 0;
	 i < Text_TableSize(w) && (i == 0 ||
				   Text_LineTable(w)[i].start_pos != 0);
	 i++)
    {
	DEBUGOUT(XdbDebug(__FILE__, w,
			  "RefigureLines: [%d] start_pos %d virt %d\n",
			  i, Text_LineTable(w)[i].start_pos,
			  Text_LineTable(w)[i].virt_line));
    }
#endif

    pos = Text_TopPos(w);
    nlines = 0;

    /* Find line to start with */
    i = 0;
    lte = Text_LineTable(w);

    if (pos)
    {
	for (i = 1, lte = Text_LineTable(w) + i;
	     i < Text_TableSize(w) && lte->start_pos;
	     i++, lte = Text_LineTable(w) + i)
	{
	    if (lte->start_pos >= pos)
	    {
		break;
	    }
	}
    }

    for (;
	 i < Text_TableSize(w) && (lte->start_pos || i == 0);
	 i++, lte = Text_LineTable(w) + i)
    {
	if (nlines >= Text_LineMax(w))
	{
	    LineIncrease(w, nlines + 16);
	}

	line = &Text_Line(w)[nlines];

	if (line->extra)
	{
	    XtFree((char *)line->extra);
	}

	extra = NULL;
	more = (*Text_Output(w)->MeasureLine) ((XmTextWidget)w, nlines,
					       pos, &next, &extra);

	line->start = lte->start_pos;
	line->changed = False;
	line->changed_position = 0;
	line->extra = extra;

	pos = next;
	nlines++;
    }

    Text_LineCount(w) = nlines;
    Text_TopLine(w) = _XmTextGetTableIndex(w, Text_TopPos(w));

    /* Not sure about this ...
     * Do we need to provide a line beyond the last real line in the text ?
     */
    if (nlines >= Text_LineMax(w))
    {
	LineIncrease(w, nlines + 16);
    }

    line = &Text_Line(w)[nlines];
    if (line->extra)
    {
	XtFree((char *)line->extra);
    }

    line->start = PASTENDPOS;	/* next wasn't good enough */
    line->changed = False;
    line->changed_position = 0;
    line->extra = NULL;
    /* End unsure part */

    if (Text_BottomPos(w) == 0)
    {
	Text_BottomPos(w) = INT_MAX;
    }

    else
    {
	Text_BottomPos(w) = line->start;
    }

    /* This is too verbose to stay on */
#ifdef VERBOSE
    if (XdbInDebug(__FILE__, (Widget)w))
    {
	int i;

	for (i = 0; i <= Text_LineCount(w); i++)
	{
	    Line line = &Text_Line(w)[i];

	    if (line->extra)
	    {
		DEBUGOUT(XdbDebug(__FILE__, (Widget)w,
				"RefigureLines: line[%d]: start=%d width=%d\n",
				  i, line->start, line->extra->width));
	    }
	    else
	    {
		DEBUGOUT(XdbDebug(__FILE__, (Widget)w,
				"RefigureLines: line[%d]: start=%d width=NA\n",
				  i, line->start));
	    }
	}
    }

#if VERBOSE
    DEBUGOUT(XdbDebug(__FILE__, (Widget)w,
		      "RefigureLines: top on line %d, bottompos %d\n",
		      i, Text_BottomPos(w)));
#endif
#endif
}

#if 0
/* This is not used anywhere. Remove ? FIX ME */
static LineNum
LineTableFindNum(XmTextWidget w, XmTextPosition pos)
{
    LineNum i;

    if (pos < Text_TopPos(w))
    {
	return NOLINE;
    }

    for (i = 0; i < Text_LineCount(w); i++)
    {
	Line line = &Text_Line(w)[i];
	Line next = &Text_Line(w)[i + 1];

	if (pos >= line->start && pos < next->start)
	{
	    return i;
	}
    }

    return NOLINE;
}
#endif

/* Line-table functions (for the whole textstring)------------------------ */

/* Running test/Xm/test6 (be sure to give it focus so something interesting
 * happens!) against Motif reveals that the line table is structured like this :
 *      - the size of its array (initially 64) is in table_size
 *      - table_index is NOT the highest used item; not sure what it's for
 *      - the array starts at the beginning of the text widget, not at the
 *        visible top. Therefore the first entry always contains 0,0.
 *      - the start_pos field obviously points to the first position of the line
 *      - the virt_line field is 1 if this is a line that's not really there in
 *        the text; it is however a line created by wrapping.
 *      - the final entry in the list has 0 start_pos.
 *
 * It also turns out that there's at least *three* places in the XmText
 *      record where stuff is stored for every line :
 *      - the text itself (in the source) as a normal string
 *      - an array of "Line"s
 *      - a LineTable
 */
#define LINETABLE_INCREMENT	64

/*
 * The block and update parameters are currently unused because I don't
 * know what they should be used for.
 */
void
_XmTextUpdateLineTable(Widget w,
		       XmTextPosition start,
		       XmTextPosition end,
		       XmTextBlock block,
		       Boolean update)
{
    XmTextWidget tw = (XmTextWidget)w;
    XmTextPosition next, ostart;
    XmTextLineTable line;
    unsigned int index;
    Boolean wrap = _XmTextShouldWordWrap(tw), next_is_virtual;

    DEBUGOUT(XdbDebug(__FILE__, w, "_XmTextUpdateLineTable start %d end %d\n",
		start, end));

    Text_NeedsRefigureLines(w) = True;
    Text_NeedsRedisplay(w) = True;

    /* Initialize ourselves */
    if (start == 0)
    {
	index = 0;
    }
    else
    {
	index = _XmTextGetTableIndex(tw, start);
	start = Text_LineTable(tw)[index].start_pos;
    }

    end = Text_LastPos(w);

    DEBUGOUT(XdbDebug(__FILE__, (Widget)w,
		      "_XmTextUpdateLineTable(start %d end %d update %s) %s\n",
		      start, end, XdbBoolean2String(update),
		      wrap ? "wrap" : ""));

    if (wrap)
    {
	/*
	 * Word-wrapping is on.
	 */
	while (end >= start)
	{
	    if (index >= Text_TableSize(w))
	    {
		int i = Text_TableSize(w);

		Text_TableSize(w) += LINETABLE_INCREMENT;
		Text_LineTable(w) = (XmTextLineTable)
		    XtRealloc((XtPointer)Text_LineTable(w),
			      sizeof(XmTextLineTableRec) * Text_TableSize(w));

		for (; i < Text_TableSize(w); i++)
		{
		    Text_LineTable(w)[i].start_pos = 0;
		    Text_LineTable(w)[i].virt_line = False;
		}
	    }

	    /*
	     * So we have ourselves a line of text. We may have to split it up
	     * visually, wrapping around at word boundaries.
	     *
	     * This first line is never a virtual one. If we pass through this
	     * inner loop a second time (or more), then those lines are
	     * virtual ones.
	     */
	    next_is_virtual = False;
	    if (start < 0)
	    {
		start = 0;
		break;
	    }
	    else
	    {
		do
		{
		    ostart = start;

		    /* FIX ME : need to fill up extra ? */
		    next = _XmTextFindLineEnd(tw, start, NULL);

		    line = Text_LineTable(w) + index;
		    line->start_pos = start;
		    line->virt_line = next_is_virtual;

		    DEBUGOUT(XdbDebug(__FILE__, (Widget)w,
		       "_XmTextUpdateLineTable: line %d start %d virtual %d\n",
				      index, line->start_pos, line->virt_line));

		    next_is_virtual = True;	/* See comment above */

		    start = next + 1;
		    index++;
		}
		while (next != PASTENDPOS && next > ostart &&
		       index < Text_TableSize(w));
	    }
	}
    }
    else
    {
	/*
	 * No word-wrapping.
	 */
	while (end >= start)
	{
	    if (index >= Text_TableSize(w))
	    {
		int i = Text_TableSize(w);

		Text_TableSize(w) += LINETABLE_INCREMENT;
		Text_LineTable(w) = (XmTextLineTable)
		    XtRealloc((char *)Text_LineTable(w),
			      sizeof(XmTextLineTableRec) * Text_TableSize(w));

		for (; i < Text_TableSize(w); i++)
		{
		    Text_LineTable(w)[i].start_pos = 0;
		    Text_LineTable(w)[i].virt_line = False;
		}
	    }

	    line = Text_LineTable(w) + index;
	    line->start_pos = start;
	    line->virt_line = False;

	    /* Be careful not to do PASTENDPOS + 1 */
	    start = (*Text_Source(w)->Scan) (Text_Source(w), start,
					  XmSELECT_LINE, XmsdRight, -1, False);

	    if (start == PASTENDPOS)
	    {
		break;		/* terminate loop */
	    }
	    else
	    {
		start++;
	    }

	    index++;
	}
    }

    /*
     * All done. Store some stuff in the widget.
     */
    Text_TotalLines(w) = index;
}

/*
 * This function is the *initialize* variant of the one above.
 */
static void
InitializeLineTable(XmTextWidget w)
{
    int i;

    /* Allocate initial amount */
    Text_LineTable(w) = (XmTextLineTable)XtMalloc(sizeof(XmTextLineTableRec)
						  * LINETABLE_INCREMENT);

    Text_TotalLines(w) = 0;
    Text_TableSize(w) = LINETABLE_INCREMENT;

    for (i = 0; i < LINETABLE_INCREMENT; i++)
    {
	Text_LineTable(w)[i].start_pos = 0;
	Text_LineTable(w)[i].virt_line = False;
    }

    _XmTextUpdateLineTable((Widget)w, 0, 0, NULL, False);
}

/* Not needed beyond this */
#undef LINETABLE_INCREMENT

unsigned int
_XmTextGetTableIndex(XmTextWidget w, XmTextPosition pos)
{
    XmTextLineTable current = Text_LineTable(w) + Text_TotalLines(w) - 1;
    unsigned int i = Text_TotalLines(w) - 1;

    if (pos < 0)
    {
	return 0;
    }

    if (Text_LineTable(w) == NULL)
    {
	return 0;
    }

    for (; current->start_pos > pos; current--, i--);

#if VERBOSE
    DEBUGOUT(XdbDebug(__FILE__, (Widget)w,
		      "XmTextGetTableIndex Pos %d Index %d\n", pos, i));
#endif

    return i;
}

/* Quasi-Public Functions ------------------------------------------------ */
void
_XmTextLineInfo(XmTextWidget w, LineNum line,
		XmTextPosition *startpos, LineTableExtra *extra)
{
    *startpos = Text_Line(w)[line].start;
    *extra = Text_Line(w)[line].extra;
}

void
_XmTextMarkRedraw(XmTextWidget w, XmTextPosition left,
		  XmTextPosition right)
{
}

LineNum
_XmTextPosToLine(XmTextWidget w, XmTextPosition position)
{
    return _XmTextGetTableIndex(w, position) + 1;
}

void
_XmTextInsert(Widget w, XmTextPosition position, char *string, XEvent *evp)
{
    XmTextStatus st;
    XmTextWidget tw = (XmTextWidget)w;
    XmTextBlockRec block;
    XmTextPosition startret, endret;

    DEBUGOUT(XdbDebug(__FILE__, w, "_XmTextInsert\n"));

    if (XtIsSubclass(w, xmTextFieldWidgetClass))
    {
	XmTextFieldInsert(w, position, string);
	return;
    }

    if (string == NULL)
    {
	return;			/* Can I do this ? FIX ME */
    }

    if (!Text_Source(w))
    {
	_XmWarning(w, "_XmTextInsert: no source\n");

	return;
    }

    block.ptr = string;
    block.length = strlen(string);
    block.format = XmFMT_8_BIT;

    startret = position;
    endret = position;

    st = (*Text_Source(w)->Replace) (tw, evp, &startret, &endret,
				     &block, True);
    /* FIX ME ?? */

    RefigureLines(tw);

    if (XtIsRealized(w))
    {
	Redisplay(tw);
    }
}

void
_XmTextSetCursorPosition(Widget w, XmTextPosition position)
{
    XmTextWidget tw = (XmTextWidget)w;
    XmTextVerifyCallbackStruct cbs;
    cbs.doit = True;
    cbs.newInsert = position;

    DEBUGOUT(XdbDebug(__FILE__, (Widget)w,
		      "_XmTextSetCursorPosition Pos %d \n",
		      position));

    if (position > Text_LastPos(w))
    {
	position = Text_LastPos(w);
    }

    if (Text_CursorPos(w) != position)
    {
	if (Text_MotionVerifyCallback(w))
	{
	    cbs.reason = XmCR_MOVING_INSERT_CURSOR;
	    cbs.event = NULL;
	    cbs.currInsert = Text_CursorPos(w);
	    cbs.startPos = cbs.endPos = 0;
	    cbs.text = NULL;

	    XtCallCallbacks(w, XmNmotionVerifyCallback, &cbs);
	}
    }

    if (cbs.doit)
    {
#if VERBOSE
	DEBUGOUT(XdbDebug(__FILE__, (Widget)w,
			  "Text_CursorPos before draw: %08x\n",
			  Text_CursorPos(w)));
#endif

	(*Text_Output(w)->DrawInsertionPoint) (tw, Text_CursorPos(w), off);

	Text_CursorPos(w) = cbs.newInsert;

#if VERBOSE
	DEBUGOUT(XdbDebug(__FILE__, (Widget)w,
			  "Text_CursorPos after draw: %08x\n",
			  Text_CursorPos(w)));
#endif

	if (Text_AutoShowCursorPosition(w))
	{
	    /* Don't do this before being realized, it'll misplace the text
	     *	(based on premature widget size).
	     *	Fixes xmcd. Danny 25/8/1997 */
	    if (XtIsRealized(w))
		XmTextShowPosition(w, Text_CursorPos(w));
	}
	else
	{
	    _XmTextMovingCursorPosition(tw, Text_CursorPos(w));
	}

	(*Text_Output(w)->DrawInsertionPoint) (tw, Text_CursorPos(w), on);
    }
}


static void
_XmTextSetEditable(Widget w, Boolean e)
{
    DEBUGOUT(XdbDebug(__FILE__, w, "_XmTextSetEditable()\n"));

    if (!XtIsRealized(w))
    {
	return;
    }

    if (e)
    {				/* becomes editable */
	Arg args[10];
	int nargs;

	XmImRegister(w, 0);

	nargs = 0;
	XtSetArg(args[nargs], XmNbackground, XtBackground(w)); nargs++;
	XtSetArg(args[nargs], XmNforeground, Prim_Foreground(w)); nargs++;
	XmImSetValues(w, args, nargs);
    }
    else
    {				/* Becomes un-editable */
	XmImUnregister(w);
    }

    _XmStringSourceSetEditable(Text_Source(w), e);
}

void
_XmTextDisableRedisplay(XmTextWidget w, Boolean losesbackingstore)
{
    Text_DisableDepth(w)++;
}

void
_XmTextEnableRedisplay(XmTextWidget w)
{
    Text_DisableDepth(w)--;
    if (Text_DisableDepth(w) == 0)
    {
	if (Text_NeedsRedisplay(w))
	{
	    Redisplay(w);
	}
    }
}

/*
 * What on earth does this do ???
 */
void
_XmTextInvalidate(XmTextWidget w, XmTextPosition position,
		  XmTextPosition topos, long delta)
{
    int i;

    for (i = 0;
	 i < Text_LineCount(w) && Text_Line(w)[i].start <= position;
	 i++);

    if (i >= Text_LineCount(w))
    {
	return;
    }

    Text_Line(w)[i - 1].changed = True;
    Text_Line(w)[i - 1].changed_position = position;

    (*Text_Output(w)->Invalidate) (w, position, topos, delta);
    (*Text_Input(w)->Invalidate) (w, position, topos, delta);
}
/* Public Functions ------------------------------------------------------ */

Widget
XmCreateText(Widget parent, char *name, Arg *arglist, Cardinal argCount)
{
    return XtCreateWidget(name, xmTextWidgetClass, parent, arglist, argCount);
}

Widget
XmCreateScrolledText(Widget parent, char *name, Arg *arglist, Cardinal argcount)
{
    Widget sw, w;
    char *sname;
    int i;
    Arg *al;

    if (name == NULL)
    {
	name = "";
    }

    sname = XtMalloc(strlen(name) + 3);
    strcpy(sname, name);
    strcat(sname, "SW");

    al = (Arg *)XtCalloc(argcount + 4, sizeof(Arg));
    for (i = 0; i < argcount; i++)
    {
	al[i].name = arglist[i].name;
	al[i].value = arglist[i].value;
    }

    XtSetArg(al[i], XmNscrollingPolicy, XmAPPLICATION_DEFINED); i++;
    XtSetArg(al[i], XmNvisualPolicy, XmVARIABLE); i++;
    XtSetArg(al[i], XmNscrollBarDisplayPolicy, XmSTATIC); i++;
    XtSetArg(al[i], XmNshadowThickness, 0); i++;

    sw = XtCreateManagedWidget(sname, xmScrolledWindowWidgetClass, parent,
			       al, i);
    XtFree((XtPointer)sname);

    i = argcount;
    XtSetArg(al[i], XmNeditMode, XmMULTI_LINE_EDIT); i++;

    w = XtCreateWidget(name, xmTextWidgetClass, sw, al, i);
    XtAddCallback(w, XmNdestroyCallback,
		  _XmDestroyParentCallback,
		  (XtPointer)w);

    XtFree((XtPointer)al);

    return w;
}

void
XmTextClearSelection(Widget w, Time time)
{
    Boolean sel;
    XmTextPosition left, right;
    XmTextBlockRec block;

    if (XtIsSubclass(w, xmTextWidgetClass))
    {
	sel = (*Text_Source(w)->GetSelection) (Text_Source(w), &left, &right);
	if (sel)
	{
		_XmTextDelete((XmTextWidget)w, NULL, left, right);
	}
	return;
    }
    else if (XtIsSubclass(w, xmTextFieldWidgetClass))
    {
	XmTextFieldClearSelection(w, time);
	return;
    }

    _XmWarning(w, "XmTextClearSelection: widget has invalid class");
}

Boolean
XmTextCopy(Widget w, Time time)
{
    _XmWarning(w, "XmTextCopy: not implemented");
    return False;		/* FIX ME */
}

Boolean
XmTextCut(Widget w, Time time)
{
    _XmWarning(w, "XmTextCut: not implemented");
    return False;		/* FIX ME */
}

Boolean
XmTextFindString(Widget w, XmTextPosition start, char *string,
		 XmTextDirection direction, XmTextPosition *position)
{
    char *buf;
    char *str;

    if ((start < 0) || (direction != XmTEXT_FORWARD))
    {
	return False;
    }

    buf = XmTextGetString(w);

    if (start > strlen(buf))
    {
	str = (char *)NULL;
    }
    else
    {
	str = strstr(&buf[start], string);
    }

    if (str == (char *)NULL)
    {
	XtFree(buf);

	return False;
    }

    *str = 0;
    *position = strlen(buf);
    XtFree(buf);
    return True;
}

int
XmTextGetBaseline(Widget w)
{
    _XmWarning(w, "XmTextGetBaseline: not implemented");
    return 0;			/* FIX ME */
}


XmTextPosition
XmTextGetCursorPosition(Widget w)
{
    if (XtIsSubclass(w, xmTextWidgetClass))
    {
	return Text_CursorPos(w);
    }
    else if (XtIsSubclass(w, xmTextFieldWidgetClass))
    {
	return XmTextFieldGetCursorPosition(w);
    }

    _XmWarning(w, "XmTextGetCursorPosition: widget has invalid class");

    return 0;
}

Boolean
XmTextGetEditable(Widget w)
{
    if (XtIsSubclass(w, xmTextWidgetClass))
    {
	return Text_Editable(w);
    }
    else if (XtIsSubclass(w, xmTextFieldWidgetClass))
    {
	return XmTextFieldGetEditable(w);
    }

    _XmWarning(w, "XmTextGetEditable: widget has invalid class");

    return 0;
}

XmTextPosition
XmTextGetInsertionPosition(Widget w)
{
    if (XtIsSubclass(w, xmTextWidgetClass))
    {
	return Text_CursorPos(w);
    }
    else if (XtIsSubclass(w, xmTextFieldWidgetClass))
    {
	return XmTextFieldGetInsertionPosition(w);
    }

    _XmWarning(w, "XmTextGetInsertionPosition: widget has invalid class");

    return 0;
}

XmTextPosition
XmTextGetLastPosition(Widget w)
{
    if (XtIsSubclass(w, xmTextWidgetClass))
    {
	return Text_LastPos(w);
    }
    else if (XtIsSubclass(w, xmTextFieldWidgetClass))
    {
	return XmTextFieldGetLastPosition(w);
    }

    _XmWarning(w, "XmTextGetLastPosition: widget has invalid class");

    return 0;
}

int
XmTextGetMaxLength(Widget w)
{
    if (XtIsSubclass(w, xmTextWidgetClass))
    {
	return _XmStringSourceGetMaxLength(Text_Source(w));
    }
    else if (XtIsSubclass(w, xmTextFieldWidgetClass))
    {
	return XmTextFieldGetMaxLength(w);
    }

    _XmWarning(w, "XmTextGetMaxLength: widget has invalid class");

    return 0;
}

char *
XmTextGetSelection(Widget w)
{
    Boolean sel;
    XmTextPosition left, right;
    XmTextBlockRec block;

    if (XtIsSubclass(w, xmTextWidgetClass))
    {
	sel = (*Text_Source(w)->GetSelection) (Text_Source(w), &left, &right);
	if (!sel)
	{
	    return NULL;
	}

	(*Text_Source(w)->ReadSource) (Text_Source(w), left, right, &block);

	return block.ptr;	/* Caller must free */
    }
    else if (XtIsSubclass(w, xmTextFieldWidgetClass))
    {
	return XmTextFieldGetSelection(w);
    }

    _XmWarning(w, "XmTextGetSelection: widget has invalid class");

    return NULL;
}

Boolean
XmTextGetSelectionPosition(Widget w, XmTextPosition *left, XmTextPosition *right)
{
    if (XtIsSubclass(w, xmTextWidgetClass))
    {
	return (*Text_Source(w)->GetSelection) (Text_Source(w), left, right);
    }
    else if (XtIsSubclass(w, xmTextFieldWidgetClass))
    {
	return XmTextFieldGetSelectionPosition(w, left, right);
    }

    _XmWarning(w, "XmTextGetSelectionPosition: widget has invalid class");

    return False;
}

wchar_t *
XmTextGetSelectionWcs(Widget w)
{
    if (XtIsSubclass(w, xmTextWidgetClass))
    {
	_XmWarning(w, "XmTextGetSelectionWcs: not implemented");
	return NULL;		/* FIX ME */
    }
    else if (XtIsSubclass(w, xmTextFieldWidgetClass))
    {
	return XmTextFieldGetSelectionWcs(w);
    }

    _XmWarning(w, "XmTextGetSelectionWcs: widget has invalid class");

    return NULL;
}


char *
XmTextGetString(Widget w)
{
    if (XmIsText(w))
    {
	return _XmStringSourceGetValue(Text_Source(w), False);
    }
    else if (XmIsTextField(w))
    {
	return XmTextFieldGetString(w);
    }

    _XmWarning(w, "XmTextGetString: widget has invalid class");

    return NULL;
}

wchar_t *
XmTextGetStringWcs(Widget w)
{
    if (XmIsText(w))
    {
	return (wchar_t *)_XmStringSourceGetValue(Text_Source(w), True);
    }
    else if (XmIsTextField(w))
    {
	return XmTextFieldGetStringWcs(w);
    }

    _XmWarning(w, "XmTextGetStringWcs: widget has invalid class");

    return NULL;
}

Boolean
XmTextFindStringWcs(Widget w,
		    XmTextPosition start,
		    wchar_t *wc_string,
		    XmTextDirection direction,
		    XmTextPosition *position)
{
    _XmWarning(w, "XmTextFindStringWcs: not implemented");
    return False;
}

/*
 * XmTextGetSubstring()
 * 
 * Gets a substring of the text 
 */
int
XmTextGetSubstring(Widget w, XmTextPosition start, int num_chars,
		   int buffer_size, char *buffer)
{
    int			len;
    int			retval = XmCOPY_SUCCEEDED;
    XmTextBlockRec	block;

    if (XmIsTextField(w))
    {
	return XmTextFieldGetSubstring(w, start, num_chars,
				       buffer_size, buffer);
    }
    if (!XmIsText(w))
    {
	_XmWarning(w, "XmTextGetSubstring: widget has invalid class");
	return XmCOPY_FAILED;
    }

    if (num_chars < buffer_size)
    {
	len = num_chars;
    }
    else
    {
	len = buffer_size - 1;
	retval = XmCOPY_TRUNCATED;
    }

    (*Text_Source(w)->ReadSource) (Text_Source(w), start, start+len-1, &block);

    memcpy(buffer, block.ptr, len);
    XtFree(block.ptr);

    return retval;
}

int
XmTextGetSubstringWcs(Widget w, XmTextPosition start, int num_chars,
		      int buffer_size, wchar_t *buffer)
{
    if (XmIsTextField(w))
    {
	return XmTextFieldGetSubstringWcs(w, start, num_chars,
					  buffer_size, buffer);
    }

    if (!XmIsText(w))
    {
	_XmWarning(w, "XmTextGetSubstringWcs: widget has invalid class");

	return XmCOPY_FAILED;
    }

    _XmWarning(w, "XmTextGetSubstringWcs: not implemented");
    return XmCOPY_FAILED;
}

XmTextPosition
XmTextGetTopCharacter(Widget w)
{
    if (XtIsSubclass(w, xmTextWidgetClass))
    {
	return Text_TopPos(w);
    }
    else
    {
	_XmWarning(w, "XmTextGetTopCharacter: not implemented");
	return 0;
    }

    _XmWarning(w, "XmTextGetTopCharacter: widget has invalid class");

    return 0;
}

void
XmTextInsert(Widget w, XmTextPosition position, char *string)
{
    if (XtIsSubclass(w, xmTextWidgetClass))
    {
	_XmTextInsert(w, position, string, NULL);
    }
    else if (XtIsSubclass(w, xmTextFieldWidgetClass))
    {
	XmTextFieldInsert(w, position, string);
    }
    else
    {
	_XmWarning(w, "XmTextInsert: widget has invalid class");
    }
}


void
XmTextInsertWcs(Widget w, XmTextPosition position, wchar_t *wcstring)
{
    if (XtIsSubclass(w, xmTextWidgetClass))
    {
	_XmWarning(w, "XmTextInsertWcs: not implemented");
	;			/* FIX ME */
    }
    else if (XtIsSubclass(w, xmTextFieldWidgetClass))
    {
	XmTextFieldInsertWcs(w, position, wcstring);
    }
    else
    {
	_XmWarning(w, "XmTextInsertWcs: widget has invalid class");
    }
}

Boolean
XmTextPaste(Widget w)
{
    if (XtIsSubclass(w, xmTextWidgetClass))
    {
	_XmWarning(w, "XmTextPaste: not implemented");
	return False;		/* FIX ME */
    }
    else if (XtIsSubclass(w, xmTextFieldWidgetClass))
    {
	return XmTextFieldPaste(w);
    }
    else
    {
	_XmWarning(w, "XmTextPaste: widget has invalid class");
    }

    return False;
}

Boolean
XmTextPosToXY(Widget w, XmTextPosition position, Position *x, Position *y)
{
    if (XtIsSubclass(w, xmTextWidgetClass))
    {
	return (*Text_Output(w)->PosToXY) ((XmTextWidget)w, position, x, y);
    }
    else if (XtIsSubclass(w, xmTextFieldWidgetClass))
    {
	return XmTextFieldPosToXY(w, position, x, y);
    }

    _XmWarning(w, "XmTextPosToXY: widget has invalid class");

    return False;

}

Boolean
XmTextRemove(Widget w)
{
    if (XtIsSubclass(w, xmTextWidgetClass))
    {
	Boolean sel;
	XmTextPosition left, right;

	/* Copied part of the code of TextIn.c:DeleteForwardChar */
	sel = (*Text_Source(w)->GetSelection) (Text_Source(w), &left, &right);

	if (sel)
	{
	    _XmTextDelete((XmTextWidget)w, NULL, left, right);
	}

	return True;
    }
    else if (XtIsSubclass(w, xmTextFieldWidgetClass))
    {
	return XmTextFieldRemove(w);
    }
    else
    {
	_XmWarning(w, "XmTextRemove: widget has invalid class");
	return False;
    }
}

void
XmTextReplace(Widget w, XmTextPosition from_pos, XmTextPosition to_pos, char *value)
{
    XmTextStatus st;
    XmTextWidget tw = (XmTextWidget)w;
    XmTextBlockRec block;
    XmTextPosition startret, endret;

    if (XtIsSubclass(w, xmTextFieldWidgetClass))
    {
	XmTextFieldReplace(w, from_pos, to_pos, value);

	return;
    }
    else if (!XtIsSubclass(w, xmTextWidgetClass))
    {
	_XmWarning(w, "XmTextReplace: widget has invalid class");

	return;
    }

    DEBUGOUT(XdbDebug(__FILE__, w, "XmTextReplace(from %d to %d '%s'\n",
		      from_pos, to_pos, value));

    block.ptr = value;
    block.length = value ? strlen(value) : 0;
    block.format = XmFMT_8_BIT;

    startret = from_pos;
    endret = to_pos;

    st = (*Text_Source(w)->Replace) (tw, NULL, &startret, &endret,
				     &block, False);
    /* FIX ME ?? */

    RefigureLines(tw);

    if (XtIsRealized(w))
    {
	Redisplay(tw);
    }
}

void
XmTextReplaceWcs(Widget w, XmTextPosition from_pos, XmTextPosition to_pos,
		 wchar_t *wcstring)
{
    if (XtIsSubclass(w, xmTextFieldWidgetClass))
    {
	XmTextFieldReplaceWcs(w, from_pos, to_pos, wcstring);

	return;
    }
    else if (!XtIsSubclass(w, xmTextWidgetClass))
    {
	_XmWarning(w, "XmTextReplaceWcs: widget has invalid class");

	return;
    }

    _XmWarning(w, "XmTextReplaceWcs is not implemented");
}

void
XmTextSetAddMode(Widget w, Boolean state)
{
    if (XtIsSubclass(w, xmTextWidgetClass))
    {
	_XmWarning(w, "XmTextSetAddMode: not implemented");
	;			/* FIX ME */
    }
    else if (XtIsSubclass(w, xmTextFieldWidgetClass))
    {
	XmTextFieldSetAddMode(w, state);
    }
    else
    {
	_XmWarning(w, "XmTextSetAddMode: widget has invalid class");
    }
}

void
XmTextSetCursorPosition(Widget w, XmTextPosition position)
{
    if (XtIsSubclass(w, xmTextWidgetClass))
    {
	_XmTextSetCursorPosition(w, position);
    }
    else if (XtIsSubclass(w, xmTextFieldWidgetClass))
    {
	XmTextFieldSetCursorPosition(w, position);
    }
    else
    {
	_XmWarning(w, "XmTextSetCursorPosition: widget has invalid class");
    }
}


void
XmTextSetEditable(Widget w, Boolean editable)
{
    if (XtIsSubclass(w, xmTextFieldWidgetClass))
    {
	XmTextFieldSetEditable(w, editable);
    }
    else if (!XmIsText(w))
    {
	_XmWarning(w, "XmTextSetEditable: widget has invalid class");

	return;
    }

    if (Text_Editable(w) != editable)
    {
	_XmTextSetEditable(w, editable);
    }

    Text_Editable(w) = editable;
}

void
XmTextSetHighlight(Widget w, XmTextPosition left, XmTextPosition right, XmHighlightMode mode)
{
    if (left >= right)
    {
	/* FIX ME */
	DEBUGOUT(XdbDebug(__FILE__, w,
			  "XmTextSetHighlight %d >= %d, not sure what to do.\n",
			  left, right));

	return;
    }

    if (XtIsSubclass(w, xmTextWidgetClass))
    {
	DEBUGOUT(XdbDebug(__FILE__, w,
			  "XmTextSetHighlight(%d,%d,%s)\n",
			  left, right, XdbHighlightMode2String(mode)));

	/* FIX ME - simplistic approach for now */
	Text_Highlight(w).number = 2;
	Text_Highlight(w).list[0].position = left;
	Text_Highlight(w).list[0].mode = mode;
	Text_Highlight(w).list[1].position = right;
	Text_Highlight(w).list[1].mode = XmHIGHLIGHT_NORMAL;

	if (XtIsRealized(w))
	{
	    DoExpose(w, NULL, NULL);
	}
    }
    else if (XtIsSubclass(w, xmTextFieldWidgetClass))
    {
	XmTextFieldSetHighlight(w, left, right, mode);
    }
    else
    {
	_XmWarning(w, "XmTextSetHighlight: widget has invalid class");
    }
}

void
XmTextSetInsertionPosition(Widget w, XmTextPosition position)
{
    if (XtIsSubclass(w, xmTextFieldWidgetClass))
    {
	XmTextFieldSetCursorPosition(w, position);
    }
    else if (XtIsSubclass(w, xmTextWidgetClass))
    {
	_XmTextSetCursorPosition(w, position);
    }
    else
    {
	_XmWarning(w, "XmTextSetInsertionPosition: widget has invalid class");
    }
}

void
XmTextSetMaxLength(Widget w, int max_length)
{
    if (XtIsSubclass(w, xmTextWidgetClass))
    {
	_XmStringSourceSetMaxLength(Text_Source(w), max_length);
    }
    else if (XtIsSubclass(w, xmTextFieldWidgetClass))
    {
	XmTextFieldSetMaxLength(w, max_length);
    }
    else
    {
	_XmWarning(w, "XmTextSetMaxLength: widget has invalid class");
    }
}

void
XmTextSetSelection(Widget w, XmTextPosition first, XmTextPosition last,
		   Time time)
{
    DEBUGOUT(XdbDebug(__FILE__, w, "XmTextSetSelection(%d,%d)\n", first, last));

    if (XtIsSubclass(w, xmTextWidgetClass))
    {
	(*Text_Source(w)->SetSelection) (Text_Source(w), first, last, time);
    }
    else if (XtIsSubclass(w, xmTextFieldWidgetClass))
    {
	XmTextFieldSetSelection(w, first, last, time);
    }
    else
    {
	_XmWarning(w, "XmTextSetSelection: widget has invalid class");
    }
}

void
XmTextSetString(Widget w, char *value)
{
    XmTextWidget tw = (XmTextWidget)w;

    if (XtIsSubclass(w, xmTextFieldWidgetClass))
    {
	XmTextFieldSetString(w, value);
    }
    else if (XtIsSubclass(w, xmTextWidgetClass))
    {
	_XmStringSourceSetValue(tw, value);

	Text_LastPos(w) = (value ? strlen(value) : 0);

	DEBUGOUT(XdbDebug(__FILE__, w, "XmTextSetString(%s), lastpos %d\n",
		value, Text_LastPos(w)));

	_XmTextUpdateLineTable(w, 0, 0, NULL, False);

	RefigureLines(tw);

	(*Text_Output(tw)->Invalidate) (tw, 0, 0, 0);

	if (XtIsRealized(w))
	{
	    Redisplay(tw);
	}
    }
    else
    {
	_XmWarning(w, "XmTextSetString: widget has invalid class");
    }
}

void
XmTextSetStringWcs(Widget w, wchar_t *wcstring)
{
    if (XtIsSubclass(w, xmTextWidgetClass))
    {
	_XmWarning(w, "XmTextSetStringWcs: not implemented");
	;			/* FIX ME */
    }
    else if (XtIsSubclass(w, xmTextFieldWidgetClass))
    {
	XmTextFieldSetStringWcs(w, wcstring);
    }
    else
    {
	_XmWarning(w, "XmTextSetStringWcs: widget has invalid class");
    }
}

void
XmTextDisableRedisplay(Widget w)
{
    Text_DisableDepth(w)--;
#if 0
    _XmWarning(w, "XmTextDisableRedisplay is not implemented");
#endif
}

void
XmTextEnableRedisplay(Widget w)
{
    Text_DisableDepth(w)++;
#if 0
    _XmWarning(w, "XmTextEnableRedisplay is not implemented");
#endif
}


XmTextSource
XmTextGetSource(Widget w)
{
    return Text_Source(w);
}

void
XmTextSetSource(Widget w, XmTextSource s,
		XmTextPosition top, XmTextPosition curs)
{
    XmTextWidget tw = (XmTextWidget)w;

    DEBUGOUT(XdbDebug(__FILE__, w, "XmTextSetSource\n"));

    if (s == NULL)
    {
	_XmWarning(w, "Invalid source, source ignored.");
	return;
    }

    (*Text_Source(w)->RemoveWidget) (Text_Source(w), tw);

    Text_Source(w) = s;

    (*Text_Source(w)->AddWidget) (Text_Source(w), tw);

    _XmTextUpdateLineTable(w, 0, 0, NULL, False);

    RefigureLines(tw);

    if (XtIsRealized(w))
    {
	Redisplay(tw);
    }
}

void
XmTextScroll(Widget aw, int n)
{
    XmTextWidget w = (XmTextWidget)aw;
    int top_index, index;

    if (!XtIsSubclass((Widget)w, xmTextWidgetClass))
    {
	_XmWarning((Widget)w, "XmTextScroll: widget has invalid class");

	return;
    }

    top_index = _XmTextGetTableIndex(w, Text_TopPos(w));
    if (n < 0)
    {
	index = _XmMax(n + top_index, 0);
    }
    else
    {
	index = _XmMin(n + top_index,
		       Text_TotalLines(w) - 1) - Text_LineCount(w) + 1;
    }
    DEBUGOUT(XdbDebug(__FILE__, aw, "XmTextScroll index=%d n=%d\n", index, n));

    XmTextSetTopCharacter(aw, Text_LineTable(w)[index].start_pos);
}

void
XmTextSetTopCharacter(Widget w, XmTextPosition top_character)
{
    if (!XtIsSubclass(w, xmTextWidgetClass))
    {
	_XmWarning(w, "XmTextSetTopCharacter: widget has invalid class");

	return;
    }

    DEBUGOUT(XdbDebug(__FILE__, w, "XmTextSetTopCharacter top_character=%d\n",
		      top_character));

    if (Text_EditMode(w) == XmSINGLE_LINE_EDIT)
    {
	/* Scroll horizontally until top_character is leftmost character */
    }
    else
    {
	Text_TopPos(w) = top_character;

	RefigureLines((XmTextWidget)w);

	if (XtIsRealized(w))
	{
	    Redisplay((XmTextWidget)w);
	}
    }
}

void
XmTextShowPosition(Widget aw, XmTextPosition position)
{
    XmTextWidget w = (XmTextWidget)aw;
    unsigned int top_index, index, bottom_index;

    DEBUGOUT(XdbDebug(__FILE__, aw, "XmTextShowPosition pos=%d\n", position));

    if (XtIsSubclass(aw, xmTextFieldWidgetClass))
    {
	XmTextFieldShowPosition(aw, position);
    }
    else if (XtIsSubclass(aw, xmTextWidgetClass))
    {
	bottom_index = _XmTextGetTableIndex(w, Text_BottomPos(w));
	top_index = _XmTextGetTableIndex(w, Text_TopPos(w));
	index = _XmTextGetTableIndex(w, position);

	/* We need only be concerned with the Text_TopPos here. */

	if (index < top_index)
	{
	    ;
	}
	else if (bottom_index < index)
	{
	    /* This used to be here, but it's wrong :
		index += top_index - bottom_index;
	     */
	    index = bottom_index;
	}
	else
	{
	    index = top_index;
	}
	Text_TopPos(w) = Text_LineTable(w)[index].start_pos;

	/*
	 * ... because the Output object will do the hard work for us anyway.
	 *
	 * MakePositionVisible will (I hope) also do horizontal positioning.
	 */

	(*Text_Output(w)->MakePositionVisible) (w, position);

	if (Text_NeedsRedisplay(w))
	{
	    Redisplay(w);
	}
    }
}

XmTextPosition
XmTextXYToPos(Widget w, Position x, Position y)
{
    DEBUGOUT(XdbDebug(__FILE__, w, "XmTextXYToPos x=%d y=%d\n", x, y));

    if (XtIsSubclass(w, xmTextFieldWidgetClass))
    {
	return XmTextFieldXYToPos(w, x, y);
    }
    else if (XtIsSubclass(w, xmTextWidgetClass))
    {
	return (*Text_Output(w)->XYToPos) ((XmTextWidget)w, x, y);
    }
    else
    {
	return 0;
    }
}


void
_XmTextExportValue(Widget w, int offset, XtArgVal *value)
{
    *value = (XtArgVal)XmTextGetString(w);

    DEBUGOUT(XdbDebug(__FILE__, w,
		      "_XmTextExportValue: value '%s'\n",
		      (char *)*value));
}

/*
 * GetValues works through a whole bunch of stuff here :
 * - the "normal" mechanism : Xt will copy stuff specified in resources
 * - synthetic resources : LessTif does this through GetValuesHook on
 *      the Primitive which is our superclass. _XmTextExportValue above
 *      is an example of this.
 * - explicit call of GetValues functions in our subparts, see below.
 *      The implementations of these are where they belong (in TextIn.c
 *      and TextOut.c), and both use XtGetSubvalues.
 *
 * For the infinitely curious, the last subpart (if you want to call it that),
 *      the XmTextSource, has no resources that you can access this way. It's
 *      not an Xt Object.
 */
void
TextGetValues(Widget w, ArgList args, Cardinal *num_args)
{
    /* Call the GetValues method in our subparts. */
    if (Text_Output(w))
    {
	(*Text_Output(w)->GetValues) (w, args, *num_args);
    }

    if (Text_Input(w))
    {
	(*Text_Input(w)->GetValues) (w, args, *num_args);
    }

    /* Be verbose about what they're trying to find out */
    DEBUGOUT(XdbDebug(__FILE__, w, "TextGetValues :\n"));
    DEBUGOUT(XdbPrintArgList(__FILE__, w, args, *num_args, True));
}

/*
 * Not sure whether I need to do all this copying.
 * FIX ME
 */
static XtPointer
_XmText_TraitGetValue(Widget w, int format)
{
	DEBUGOUT(XdbDebug(__FILE__, w, "_XmText_TraitGetValue(%s)\n",
		(format == XmFORMAT_XmSTRING) ? "XmFORMAT_XmSTRING" :
		(format == XmFORMAT_MBYTE) ? "XmFORMAT_MBYTE" :
		(format == XmFORMAT_WCS) ? "XmFORMAT_WCS" : "??"));

	switch (format) {
	case XmFORMAT_XmSTRING:
		return XmStringCreateSimple(Text_Value(w));
	case XmFORMAT_MBYTE:
		return XtNewString(XmTextGetString(w)); /* FIX ME */
	case XmFORMAT_WCS:
		return XtNewString(XmTextGetString(w)); /* FIX ME */
	default:
		return NULL;
	}
}

static void
_XmText_TraitSetValue(Widget w, XtPointer value, int format)
{
	char    *s;

	DEBUGOUT(XdbDebug(__FILE__, w, "_XmText_TraitSetValue(%s)\n",
		(format == XmFORMAT_XmSTRING) ? "XmFORMAT_XmSTRING" :
		(format == XmFORMAT_MBYTE) ? "XmFORMAT_MBYTE" :
		(format == XmFORMAT_WCS) ? "XmFORMAT_WCS" : "??"));

	switch (format) {
	case XmFORMAT_XmSTRING:
	    if (XmStringGetLtoR((XmString)value, XmFONTLIST_DEFAULT_TAG, &s))
	    {
		XmTextSetString(w, s);
	    }
	    return;
	case XmFORMAT_MBYTE:
	    /* FIX ME */
	    XmTextSetString(w, value);
	    return;
	case XmFORMAT_WCS:
	    /* FIX ME */
	    XmTextSetString(w, value);
	    return;
	default:
	    return;
	}
}

static int
_XmText_TraitPreferredFormat(Widget w)
{
	DEBUGOUT(XdbDebug(__FILE__, w, "_XmText_TraitPreferredFormat\n"));

	return XmFORMAT_WCS;
}
