#define	NO_TRAITS
/**
 *
 * $Id: TextF.c,v 1.3 1997/09/04 22:41:16 u27113 Exp $
 *
 * Copyright (C) 1995 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[] = "$Id: TextF.c,v 1.3 1997/09/04 22:41:16 u27113 Exp $";

#undef	USE_SHARED_GC

#undef	USE_AVERAGE_WIDTH
#define	TextF_FontMaxWidth(w)	TextF_Font(w)->max_bounds.width

#include <LTconfig.h>
#include <XmI/XmI.h>

#include <Xm/XmP.h>
#include <Xm/ScreenP.h>
#include <Xm/TextFP.h>
#include <Xm/TransltnsP.h>
#include <X11/Xatom.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>

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

#include <XmI/DebugUtil.h>

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

#define	DBG(a) \
	DEBUGOUT(XdbDebug(__FILE__, NULL, "%s\n", a))
#define DBGW(a) \
	DEBUGOUT(XdbDebug(__FILE__, (Widget)w, "%s\n", a))
#define DBG1(a,b) \
	DEBUGOUT(XdbDebug(__FILE__, (Widget)w, "%s: %d\n", a, (int)b))
#define DBG2(a,b,c) \
	DEBUGOUT(XdbDebug(__FILE__, (Widget)w, "%s: %d %d\n", a, (int)b,(int)c))

static void _XmTextFieldSetEditable(Widget w, Boolean e);

static void class_initialize();

static void class_part_initialize(WidgetClass w_class);

static void initialize(Widget, Widget, ArgList, Cardinal *);

static void destroy(Widget w);

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

static void resize(Widget w);

static Boolean set_values(Widget, Widget, Widget, ArgList, Cardinal *);

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

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

#define Offset(field) XtOffsetOf(XmTextFieldRec, text.field)
#define OffsetOf(rec,field) XtOffsetOf(XmTextFieldRec, rec.field)

/* Resources for the TextField class */
static XtResource resources[] =
{
    {
	XmNactivateCallback, XmCCallback, XmRCallback,
	sizeof(XtCallbackList), Offset(activate_callback),
	XmRCallback, (XtPointer)NULL
    },
    {
	XmNlosingFocusCallback, XmCCallback, XmRCallback,
	sizeof(XtCallbackList), Offset(losing_focus_callback),
	XmRCallback, (XtPointer)NULL
    },
    {
	XmNfocusCallback, XmCCallback, XmRCallback,
	sizeof(XtCallbackList), Offset(focus_callback),
	XmRCallback, (XtPointer)NULL
    },
    {
	XmNmodifyVerifyCallback, XmCCallback, XmRCallback,
	sizeof(XtCallbackList), Offset(modify_verify_callback),
	XtRCallback, (XtPointer)NULL
    },
    {
	XmNmodifyVerifyCallbackWcs, XmCCallback, XmRCallback,
	sizeof(XtCallbackList), Offset(wcs_modify_verify_callback),
	XtRCallback, (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
    },
    {
	XmNvalueChangedCallback, XmCCallback, XmRCallback,
	sizeof(XtCallbackList), Offset(value_changed_callback),
	XmRCallback, (XtPointer)NULL
    },
    {
	XmNvalue, XmCValue, XmRString,
	sizeof(String), Offset(value),
	XtRImmediate, (XtPointer)XmUNSPECIFIED
	/* FIX ME: Motif has XmRString, wacky value here */
    },
    {
	XmNvalueWcs, XmCValueWcs, XmRValueWcs,
	sizeof(wchar_t *), Offset(wc_value),
	XmRString, (XtPointer)NULL
    },
    {
	XmNmarginHeight, XmCMarginHeight, XmRVerticalDimension,
	sizeof(Dimension), Offset(margin_height),
	XmRImmediate, (XtPointer)5
    },
    {
	XmNmarginWidth, XmCMarginWidth, XmRHorizontalDimension,
	sizeof(Dimension), Offset(margin_width),
	XmRImmediate, (XtPointer)5
    },
    {
	XmNcursorPosition, XmCCursorPosition, XmRTextPosition,
	sizeof(XmTextPosition), Offset(cursor_position),
	XmRImmediate, (XtPointer)0
    },
    {
	XmNcolumns, XmCColumns, XmRShort,
	sizeof(short), Offset(columns),
	XmRImmediate, (XtPointer)20
    },
    {
	XmNmaxLength, XmCMaxLength, XmRInt,
	sizeof(int), Offset(max_length),
	XmRImmediate, (XtPointer)INT_MAX
    },
    {
	XmNblinkRate, XmCBlinkRate, XmRInt,
	sizeof(int), Offset(blink_rate),
	XmRImmediate, (XtPointer)500
    },
    {
	XmNfontList, XmCFontList, XmRFontList,
	sizeof(XmFontList), Offset(font_list),
	XmRImmediate, (XtPointer)XmUNSPECIFIED
    },
    {
	XmNselectionArray, XmCSelectionArray, XmRPointer,
	sizeof(XtPointer), Offset(selection_array),
	XmRImmediate, (XtPointer)NULL
	/* FIX ME: Motif has XmRInt, wacky value here */
    },
    {
	XmNselectionArrayCount, XmCSelectionArrayCount, XmRInt,
	sizeof(int), Offset(selection_array_count),
	XmRImmediate, (XtPointer)3
	/* FIX ME: Motif has XmRInt, (XtPointer)whacko value here */
    },
    {
	XmNresizeWidth, XmCResizeWidth, XmRBoolean,
	sizeof(Boolean), Offset(resize_width),
	XmRImmediate, (XtPointer)False
    },
    {
	XmNpendingDelete, XmCPendingDelete, XmRBoolean,
	sizeof(Boolean), Offset(pending_delete),
	XmRImmediate, (XtPointer)True
    },
    {
	XmNeditable, XmCEditable, XmRBoolean,
	sizeof(Boolean), Offset(editable),
	XmRImmediate, (XtPointer)True
    },
    {
	XmNcursorPositionVisible, XmCCursorPositionVisible, XmRBoolean,
	sizeof(Boolean), Offset(cursor_position_visible),
	XmRImmediate, (XtPointer)True
    },
    {
	XmNverifyBell, XmCVerifyBell, XmRBoolean,
	sizeof(Boolean), Offset(verify_bell),
	XmRImmediate, (XtPointer)((unsigned char)XmUNSPECIFIED)
    },
    {
	XmNselectThreshold, XmCSelectThreshold, XmRInt,
	sizeof(int), Offset(threshold),
	XmRImmediate, (XtPointer)5
    },
    {
	XmNnavigationType, XmCNavigationType, XmRNavigationType,
sizeof(XmNavigationType), XtOffsetOf(XmTextFieldRec, 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),
	NULL /* FIX ME */ , NULL
    },
    {
	XmNvalueWcs,
	sizeof(wchar_t *), Offset(wc_value),
	NULL /* FIX ME */ , NULL
    },
};

#undef Offset
#undef OffsetOf

static void TextSet(XmTextFieldWidget w, char *s);
static void Draw(XmTextFieldWidget w);
static void DrawAll(XmTextFieldWidget w);
static void DrawInsert(XmTextFieldWidget w);
static void MassiveChangeDraw(XmTextFieldWidget w);
static void DrawTextReposition(XmTextFieldWidget);
static void ClearHighlight(XmTextFieldWidget w);
static void DrawHighlight(XmTextFieldWidget w);
static void CursorDraw(XmTextFieldWidget w);
static void CursorErase(XmTextFieldWidget w);
static Boolean CursorPosition(XmTextFieldWidget w);
static Boolean CursorMassiveAdjust(XmTextFieldWidget w);
static void CursorSet(XmTextFieldWidget w, Boolean focus);
static void VerifyBell(XmTextFieldWidget w);
static void PrimarySelectionComplete(XmTextFieldWidget w, Time time);

void _XmTextFieldFocusIn(Widget, XEvent *, String *, Cardinal *);
void _XmTextFieldFocusOut(Widget, XEvent *, String *, Cardinal *);
static void activate(Widget, XEvent *, String *, Cardinal *);
static void backward_character(Widget, XEvent *, String *, Cardinal *);
static void backward_word(Widget, XEvent *, String *, Cardinal *);
static void beep(Widget, XEvent *, String *, Cardinal *);
static void beginning_of_line(Widget, XEvent *, String *, Cardinal *);
static void clear_selection(Widget, XEvent *, String *, Cardinal *);
static void copy_clipboard(Widget, XEvent *, String *, Cardinal *);
static void copy_primary(Widget, XEvent *, String *, Cardinal *);
static void copy_to(Widget, XEvent *, String *, Cardinal *);
static void cut_clipboard(Widget, XEvent *, String *, Cardinal *);
static void cut_primary(Widget, XEvent *, String *, Cardinal *);
static void delete_next_character(Widget, XEvent *, String *, Cardinal *);
static void delete_previous_character(Widget, XEvent *, String *, Cardinal *);
static void delete_next_word(Widget, XEvent *, String *, Cardinal *);
static void delete_previous_word(Widget, XEvent *, String *, Cardinal *);
static void delete_selection(Widget, XEvent *, String *, Cardinal *);
static void delete_to_end_of_line(Widget, XEvent *, String *, Cardinal *);
static void delete_to_start_of_line(Widget, XEvent *, String *, Cardinal *);
static void delete_all(Widget, XEvent *, String *, Cardinal *);
static void deselect_all(Widget, XEvent *, String *, Cardinal *);
static void do_quick_action(Widget, XEvent *, String *, Cardinal *);
static void end_of_line(Widget, XEvent *, String *, Cardinal *);
static void enter(Widget, XEvent *, String *, Cardinal *);
static void extend_adjust(Widget, XEvent *, String *, Cardinal *);
static void extend_end(Widget, XEvent *, String *, Cardinal *);
static void extend_start(Widget, XEvent *, String *, Cardinal *);
static void forward_character(Widget, XEvent *, String *, Cardinal *);
static void forward_word(Widget, XEvent *, String *, Cardinal *);
static void grab_focus(Widget, XEvent *, String *, Cardinal *);
static void Help(Widget, XEvent *, String *, Cardinal *);
static void insert_string(Widget, XEvent *, String *, Cardinal *);
static void key_select(Widget, XEvent *, String *, Cardinal *);
static void kill_next_character(Widget, XEvent *, String *, Cardinal *);
static void kill_next_word(Widget, XEvent *, String *, Cardinal *);
static void kill_previous_character(Widget, XEvent *, String *, Cardinal *);
static void kill_previous_word(Widget, XEvent *, String *, Cardinal *);
static void kill_selection(Widget, XEvent *, String *, Cardinal *);
static void kill_to_end_of_line(Widget, XEvent *, String *, Cardinal *);
static void kill_to_start_of_line(Widget, XEvent *, String *, Cardinal *);
static void leave(Widget, XEvent *, String *, Cardinal *);
static void move_destination(Widget, XEvent *, String *, Cardinal *);
static void move_to(Widget, XEvent *, String *, Cardinal *);
static void next_tab_group(Widget, XEvent *, String *, Cardinal *);
static void page_left(Widget, XEvent *, String *, Cardinal *);
static void page_right(Widget, XEvent *, String *, Cardinal *);
static void paste_clipboard(Widget, XEvent *, String *, Cardinal *);
static void paste_primary(Widget, XEvent *, String *, Cardinal *);
static void prev_tab_group(Widget, XEvent *, String *, Cardinal *);
static void process_bdrag(Widget, XEvent *, String *, Cardinal *);
static void process_cancel(Widget, XEvent *, String *, Cardinal *);
static void process_home(Widget, XEvent *, String *, Cardinal *);
static void process_return(Widget, XEvent *, String *, Cardinal *);
static void process_tab(Widget, XEvent *, String *, Cardinal *);
static void quick_copy_set(Widget, XEvent *, String *, Cardinal *);
static void quick_cut_set(Widget, XEvent *, String *, Cardinal *);
static void redraw_display(Widget, XEvent *, String *, Cardinal *);
static void secondary_adjust(Widget, XEvent *, String *, Cardinal *);
static void secondary_notify(Widget, XEvent *, String *, Cardinal *);
static void secondary_start(Widget, XEvent *, String *, Cardinal *);
static void select_adjust(Widget, XEvent *, String *, Cardinal *);
static void select_all(Widget, XEvent *, String *, Cardinal *);
static void select_end(Widget, XEvent *, String *, Cardinal *);
static void select_start(Widget, XEvent *, String *, Cardinal *);
static void self_insert(Widget, XEvent *, String *, Cardinal *);
static void set_anchor(Widget, XEvent *, String *, Cardinal *);
static void set_insertion_point(Widget, XEvent *, String *, Cardinal *);
static void set_selection_hint(Widget, XEvent *, String *, Cardinal *);
static void toggle_add_mode(Widget, XEvent *, String *, Cardinal *);
static void traverse_home(Widget, XEvent *, String *, Cardinal *);
static void traverse_next(Widget, XEvent *, String *, Cardinal *);
static void traverse_prev(Widget, XEvent *, String *, Cardinal *);
static void unkill(Widget, XEvent *, String *, Cardinal *);
static void unmap(Widget, XEvent *, String *, Cardinal *);

/* action table table */

/* MLM FIX ME -- the EventBindings[1-2] (Transltns.c) are
 * current unused. */
static XtActionsRec actions[] =
{
    {"activate", activate},
    {"backward-character", backward_character},
    {"backward-word", backward_word},
    {"beep", beep},
    {"beginning-of-line", beginning_of_line},
    {"clear-selection", clear_selection},
    {"copy-clipboard", copy_clipboard},
    {"copy-primary", copy_primary},
    {"copy-to", copy_to},
    {"cut-clipboard", cut_clipboard},
    {"cut-primary", cut_primary},
    {"delete-next-character", delete_next_character},
    {"delete-previous-character", delete_previous_character},
    {"delete-next-word", delete_next_word},
    {"delete-previous-word", delete_previous_word},
    {"delete-selection", delete_selection},
    {"delete-to-end-of-line", delete_to_end_of_line},
    {"delete-to-start-of-line", delete_to_start_of_line},
    {"delete-all", delete_all},
    {"deselect-all", deselect_all},
    {"do-quick-action", do_quick_action},
    {"end-of-line", end_of_line},
    {"enter", enter},
    {"extend-adjust", extend_adjust},
    {"extend-end", extend_end},
    {"extend-start", extend_start},
    {"forward-character", forward_character},
    {"forward-word", forward_word},
    {"grab-focus", grab_focus},
    {"Help", Help},
    {"insert-string", insert_string},
    {"key-select", key_select},
    {"kill-next_character", kill_next_character},
    {"kill-next-word", kill_next_word},
    {"kill-previous-character", kill_previous_character},
    {"kill-previous-word", kill_previous_word},
    {"kill-selection", kill_selection},
    {"kill-to-end-of-line", kill_to_end_of_line},
    {"kill-to-start-of-line", kill_to_start_of_line},
    {"leave", leave},
    {"move-destination", move_destination},
    {"move-to", move_to},
    {"next-tab-group", next_tab_group},
    {"page-left", page_left},
    {"page-right", page_right},
    {"paste-clipboard", paste_clipboard},
    {"paste-primary", paste_primary},
    {"prev-tab-group", prev_tab_group},
    {"process-bdrag", process_bdrag},
    {"process-cancel", process_cancel},
    {"process-home", process_home},
    {"process-return", process_return},
    {"process-tab", process_tab},
    {"quick-copy-set", quick_copy_set},
    {"quick-cut-set", quick_cut_set},
    {"redraw-display", redraw_display},
    {"secondary-adjust", secondary_adjust},
    {"secondary-notify", secondary_notify},
    {"secondary-start", secondary_start},
    {"select-adjust", select_adjust},
    {"select-all", select_all},
    {"select-end", select_end},
    {"select-start", select_start},
    {"self-insert", self_insert},
    {"set-anchor", set_anchor},
    {"set-insertion-point", set_insertion_point},
    {"set-selection-hint", set_selection_hint},
    {"toggle-add-mode", toggle_add_mode},
    {"traverse-home", traverse_home},
    {"traverse-next", traverse_next},
    {"traverse-prev", traverse_prev},
    {"unkill", unkill},
    {"unmap", unmap},
    {"focusIn", _XmTextFieldFocusIn},
    {"focusOut", _XmTextFieldFocusOut}
};
/* *INDENT-OFF* */
static XmBaseClassExtRec _XmTextFCoreClassExtRec =
{
    /* next_extension            */ NULL,
    /* record_type               */ NULLQUARK,
    /* version                   */ XmBaseClassExtVersion,
    /* size                      */ sizeof(XmBaseClassExtRec),
    /* initialize_prehook        */ NULL,
    /* set_values_prehook        */ NULL,
    /* initialize_posthook       */ NULL,
    /* set_values_posthook       */ NULL,
    /* secondary_object_class    */ NULL,
    /* secondary_object_create   */ NULL,
    /* get_secondary_resources   */ NULL,
    /* fast_subclass             */ {0},
    /* get_values_prehook        */ NULL,
    /* get_values_posthook       */ NULL,
    /* class_part_init_prehook   */ NULL,
    /* class_part_init_posthook  */ NULL,
    /* ext_resources             */ NULL,
    /* compiled_ext_resources    */ NULL,
    /* num_ext_resources         */ 0,
    /* use_sub_resources         */ False,
    /* widget_navigable          */ 0,/******XmInheritWidgetNavigable,*/
    /* focus_change              */ 0,/******XmInheritFocusChange,*/
    /* wrapper_data              */ NULL
};

XmPrimitiveClassExtRec _XmTextFPrimClassExtRec =
{
    /* next_extension      */ NULL,
    /* record_type         */ NULLQUARK,
    /* version             */ XmPrimitiveClassExtVersion,
    /* record_size         */ sizeof(XmPrimitiveClassExtRec),
    /* widget_baseline     */ NULL, /* FIX ME */
    /* widget_display_rect */ NULL, /* FIX ME */
    /* widget_margins      */ NULL  /* FIX ME */
};

XmTextFieldClassRec xmTextFieldClassRec =
{
    /* Core class part */
  {
	/* superclass            */ (WidgetClass) & xmPrimitiveClassRec,
	/* class_name            */ "XmTextField",
	/* widget_size           */ sizeof(XmTextFieldRec),
	/* class_initialize      */ class_initialize,
	/* class_part_initialize */ class_part_initialize,
	/* class_inited          */ False,
	/* initialize            */ initialize,
	/* initialize_hook       */ NULL,
	/* realize               */ realize,
	/* actions               */ actions,
	/* num_actions           */ XtNumber(actions),
	/* 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                */ expose,
	/* set_values            */ set_values,
	/* set_values_hook       */ NULL,
	/* set_values_almost     */ 0,/************XtInheritSetValuesAlmost,*/
	/* get_values_hook       */ NULL,
	/* accept_focus          */ NULL,
	/* version               */ XtVersion,
	/* callback offsets      */ NULL,
	/* tm_table              */ _XmTextF_EventBindings1,
	/* query_geometry        */ query_geometry,
	/* display_accelerator   */ 0,/***********XtInheritDisplayAccelerator,*/
	/* extension             */ (XtPointer) & _XmTextFCoreClassExtRec
  },
    /* Primitive Class part */
  {
	/* border_highlight      */ 0,/******XmInheritBorderHighlight,*/
	/* border_unhighlight    */ 0,/*******XmInheritBorderUnhighlight,*/
	/* translations          */ NULL,	/* FIX ME */
	/* arm_and_activate_proc */ 0,/********XmInheritArmAndActivate,*/
	/* synthetic resources   */ syn_resources,
	/* num syn res           */ XtNumber(syn_resources),
	/* extension             */ (XtPointer) & _XmTextFPrimClassExtRec,
  },
    /* TextField Class part */
  {
	/* extension */ NULL
  }
};
/* *INDENT-ON* */


int AMIWIN_TextF(void)
{
_XmTextFCoreClassExtRec.widgetNavigable=XmInheritWidgetNavigable;
_XmTextFCoreClassExtRec.focusChange=XmInheritFocusChange;

xmTextFieldClassRec.border_highlight=XmInheritBorderHighlight;
xmTextFieldClassRec.border_unhighlight=XmInheritBorderUnhighlight;
xmTextFieldClassRec.arm_and_activate=XmInheritArmAndActivate;
xmTextFieldClassRec.set_values_almost=XtInheritSetValuesAlmost;
xmTextFieldClassRec.display_accelerator=XtInheritDisplayAccelerator;
return(0);
}


WidgetClass xmTextFieldWidgetClass = (WidgetClass)&xmTextFieldClassRec;


/*
 * Common initialization procedures -------------------------------------------
 */

static void
FontSize(XmTextFieldWidget w)
{
    XmFontListEntry entry = NULL;
    XFontStruct *fs;
    int i;

    for (i = 0; TextF_FontList(w)[i].tag != NULL; i++)
    {
	if (!strcmp(XmFONTLIST_DEFAULT_TAG, TextF_FontList(w)[i].tag))
	{
	    entry = &TextF_FontList(w)[i];
	    break;
	}
    }

    if (!entry)
    {
	TextF_FontList(w) = entry =
	    _XmFontListCreateDefault(XtDisplay((Widget)w));
    }

    if (entry->type == XmFONT_IS_FONTSET)
    {
	XFontStruct **foo;
	char **bar;

	if (XFontsOfFontSet((XFontSet)(entry->font), &foo, &bar) < 1)
	{
	    fs = NULL;
	}
        else
        {
	    fs = foo[0];
        }
    }
    else
    {
	fs = (XFontStruct *)entry->font;
    }
    TextF_Font(w) = fs;
    TextF_FontHeight(w) = TextF_FontAscent(w) + TextF_FontDescent(w);
    TextF_FontAverageWidth(w) =
	(fs->max_bounds.width + fs->min_bounds.width) / 2;

    if (XdbInDebug(__FILE__, (Widget)w))
    {
	DEBUGOUT(XdbDebug(__FILE__, (Widget)w,
		      "FontInit: ascent=%d descent=%d height=%d avewidth=%d\n",
			  TextF_FontAscent(w), TextF_FontDescent(w),
			  TextF_FontHeight(w), TextF_FontAverageWidth(w)));
    }
}

static void
FontInitialize(XmTextFieldWidget w)
{
    /* If FontList is NULL, track up the widget heirarchy for a VendorShell
     * or a BulletinBoard & use that FontList
     */
    if (!TextF_FontList(w))
    {
	Widget parent = XtParent(w);

	while (parent)
	{
	    if (XmIsBulletinBoard(parent) || XmIsVendorShell(parent))
	    {
		XtVaGetValues(parent,
			      XmNtextFontList, &TextF_FontList(w),
			      NULL);
		TextF_FontListCreated(w) = False;
		break;
	    }

	    parent = XtParent(parent);
	}
    }

    /* If the FontList is still NULL or we have an unspecified font, use
     * the default.
     */
    if (!TextF_FontList(w) || (TextF_FontList(w) == (XmFontList)XmUNSPECIFIED))
    {
	TextF_FontList(w) = _XmGetDefaultFontList((Widget)w, XmTEXT_FONTLIST);

	/* we didn't create it, so don't free */
	TextF_FontListCreated(w) = False;
    }
    else
    {
	/* we created this, so free it when the time comes */
	TextF_FontListCreated(w) = True;
    }

    FontSize(w);
}

static void
GCInitialize(XmTextFieldWidget w)
{
    XGCValues values;
    XtGCMask mask, dynamic, dontcare;

    /*
     * DrawGC
     *      Need to change :        ClipRectangles
     */
    values.line_style = LineSolid;
    values.line_width = 0;
    values.fill_style = FillSolid;
    values.font = TextF_Font(w)->fid;
    values.foreground = Prim_Foreground(w);
    values.background = XtBackground(w);
    values.clip_x_origin = 0;
    values.clip_y_origin = 0;
    mask = GCLineStyle | GCLineWidth | GCFillStyle | GCFont |
	GCForeground | GCBackground;
    dynamic = GCClipMask | GCClipXOrigin | GCClipYOrigin |
	GCForeground | GCBackground;
    dontcare = 0;
#ifdef	USE_SHARED_GC
    TextF_DrawGC(w) = XtAllocateGC((Widget)w, 0, mask, &values,
				   dynamic, dontcare);
#else
    TextF_DrawGC(w) = XCreateGC(XtDisplay(w), XtWindow(w), mask, &values);
#endif
    TextF_DrawGCInverted(w) = False;

    /*
     * Cursor GC
     *      Need to change :        Tile/Stipple Origin, Stipple
     */
    values.line_style = LineSolid;
    values.line_width = 0;
    values.fill_style = FillStippled;
    values.foreground = Prim_Foreground(w);
    values.background = XtBackground(w);
    mask = GCLineStyle | GCLineWidth | GCFillStyle |
	GCForeground | GCBackground;
    dynamic = GCTileStipXOrigin | GCTileStipYOrigin | GCStipple;
    dontcare = 0;
#ifdef	USE_SHARED_GC
    TextF_CursorGC(w) = XtAllocateGC((Widget)w, 0, mask, &values,
				     dynamic, dontcare);
#else
    TextF_CursorGC(w) = XCreateGC(XtDisplay(w), XtWindow(w), mask, &values);
#endif

    /*
     * CopyGC
     *      At least this one is not changed anywhere :-)
     */
    values.line_style = LineSolid;
    values.line_width = 0;
    values.fill_style = FillSolid;
    values.foreground = XtBackground(w);
    values.background = Prim_Foreground(w);
    mask = GCLineStyle | GCLineWidth | GCFillStyle |
	GCForeground | GCBackground;

    TextF_CopyGC(w) = XtGetGC((Widget)w, mask, &values);
}

static void
GCPixmap(XmTextFieldWidget w)
{
    static char dots[] =
    {2, 1, 1};
    GC gc;
    int width, width_erase, height;
    Display *display;
    XGCValues values;
    XtGCMask mask;

    values.line_style = LineSolid;
    values.line_width = 0;
    values.fill_style = FillSolid;
    values.foreground = 0;
    values.background = 0;

    display = XtDisplay((Widget)w);
    width = 5;
    height = TextF_FontHeight(w);
    width_erase = 2 * TextF_Font(w)->max_bounds.width;

    if (TextF_CursorIBeam(w))
    {
	XFreePixmap(XtDisplay((Widget)w), TextF_CursorIBeam(w));
    }

    TextF_CursorIBeam(w) = (Pixmap)NULL;
    if (TextF_CursorStipple(w))
    {
	XFreePixmap(XtDisplay((Widget)w), TextF_CursorStipple(w));
    }

    TextF_CursorStipple(w) = (Pixmap)NULL;
    if (TextF_CursorSave(w))
    {
	XFreePixmap(XtDisplay((Widget)w), TextF_CursorSave(w));
    }

    TextF_CursorSave(w) = (Pixmap)NULL;
    TextF_CursorSaveValid(w) = False;

    if (height > 0)
    {
	TextF_CursorIBeam(w) =
	    XCreatePixmap(display,
			  RootWindowOfScreen(XtScreen((Widget)w)),
			  width, height, 1);

	TextF_CursorStipple(w) =
	    XCreatePixmap(display,
			  RootWindowOfScreen(XtScreen((Widget)w)),
			  width, height, 1);

	TextF_CursorSave(w) =
	    XCreatePixmap(display,
			  RootWindowOfScreen(XtScreen((Widget)w)),
			  width_erase, height, w->core.depth);

	values.line_style = LineSolid;
	values.line_width = 0;
	values.fill_style = FillSolid;
	values.foreground = 0;
	values.background = 0;
	mask = GCLineStyle | GCLineWidth | GCFillStyle |
	    GCForeground | GCBackground;
	gc = XCreateGC(display, TextF_CursorIBeam(w), mask, &values);

	XFillRectangle(display, TextF_CursorIBeam(w), gc,
		       0, 0, width, height);
	XFillRectangle(display, TextF_CursorStipple(w), gc,
		       0, 0, width, height);

	XSetForeground(display, gc, 1);
	XDrawLine(display, TextF_CursorIBeam(w), gc,
		  2, 0, 2, height - 2);
	XDrawLine(display, TextF_CursorIBeam(w), gc,
		  0, 0, 4, 0);
	XDrawLine(display, TextF_CursorIBeam(w), gc,
		  0, height - 2, 4, height - 2);

	XSetLineAttributes(display, gc, 0, LineOnOffDash, CapRound, JoinRound);
	XSetDashes(display, gc, 0, &dots[1], (int)dots[0]);
	XDrawLine(display, TextF_CursorStipple(w), gc,
		  2, 0, 2, height - 2);
	XDrawLine(display, TextF_CursorStipple(w), gc,
		  1, 0, 3, 0);
	XDrawLine(display, TextF_CursorStipple(w), gc,
		  1, height - 2, 3, height - 2);

	XFreeGC(display, gc);
    }
}

static void
GCClip(XmTextFieldWidget w)
{
    XRectangle clip;

    clip.x = 0;
    clip.y = 0;
    clip.width = TextF_ViewWidth(w);
    clip.height = TextF_ViewHeight(w);

    /* These calls change the GCs */
    XSetClipRectangles(XtDisplay((Widget)w), TextF_DrawGC(w),
		       TextF_XDraw(w), TextF_YDraw(w), &clip, 1, Unsorted);

    GCPixmap(w);

    CursorSet(w, TextF_HasFocus(w));
}

static void
SizeRecalc(XmTextFieldWidget w)
{
    TextF_ViewWidth(w) = XtWidth(w) -
	2 * Prim_ShadowThickness(w) - 2 * Prim_HighlightThickness(w) -
	2 * TextF_MarginWidth(w);

    TextF_XDraw(w) = Prim_ShadowThickness(w) + Prim_HighlightThickness(w) +
	TextF_MarginWidth(w);

    TextF_YDraw(w) = Prim_ShadowThickness(w) + Prim_HighlightThickness(w) +
	TextF_MarginHeight(w);

    TextF_YOffset(w) = TextF_YDraw(w) + TextF_FontAscent(w);

    TextF_ViewHeight(w) = TextF_FontHeight(w);

    if (TextF_YDraw(w) + TextF_ViewHeight(w) >
	XtHeight(w) - Prim_HighlightThickness(w) - Prim_ShadowThickness(w))
    {
	TextF_ViewHeight(w) = XtHeight(w) - TextF_YDraw(w) -
	    Prim_HighlightThickness(w) - Prim_ShadowThickness(w);
    }

#ifdef	USE_AVERAGE_WIDTH
    TextF_Columns(w) = (XtWidth(w)
			- 2 * Prim_ShadowThickness(w)
			- 2 * TextF_MarginWidth(w)) / TextF_FontAverageWidth(w);
#else
    if (TextF_FontMaxWidth(w))
    TextF_Columns(w) = (XtWidth(w)
			- 2 * Prim_ShadowThickness(w)
			- 2 * TextF_MarginWidth(w)) / TextF_FontMaxWidth(w);
    else if (TextF_FontAverageWidth(w))
    TextF_Columns(w) = (XtWidth(w)
			- 2 * Prim_ShadowThickness(w)
			- 2 * TextF_MarginWidth(w)) / TextF_FontAverageWidth(w);
#endif

    if (XdbInDebug(__FILE__, (Widget)w))
    {
	DEBUGOUT(XdbDebug(__FILE__, (Widget)w,
	  "SizeRecalc : width: core=%d View=%d shadow=%d margin=%d xdraw=%d\n",
		       XtWidth(w), TextF_ViewWidth(w), Prim_ShadowThickness(w),
			  TextF_MarginWidth(w), TextF_XDraw(w)));

	DEBUGOUT(XdbDebug(__FILE__, (Widget)w,
	 "SizeRecalc : height: core=%d View=%d shadow=%d margin=%d ydraw=%d\n",
		     XtHeight(w), TextF_ViewHeight(w), Prim_ShadowThickness(w),
			  TextF_MarginHeight(w), TextF_YDraw(w)));

	DEBUGOUT(XdbDebug(__FILE__, (Widget)w,
			  "SizeRecalc : YOffset=%d\n", TextF_YOffset(w)));
    }
}



/*
 * Methods --------------------------------------------------------------------
 */

/* Trait record */
XmAccessTextualTraitRec	_XmTextFTraitRec =
	{	/* version */		0,
		/* getValue */		_XmTextF_TraitGetValue,
		/* setValue */		_XmTextF_TraitSetValue,
		/* preferredFormat */	_XmTextF_TraitPreferredFormat,
};

static void
class_initialize()
{
    /* register type converter for XmStrings */
    DBG("class_initialize");

    _XmTextFCoreClassExtRec.record_type = XmQmotif;

    XtSetTypeConverter(XtRString,	/* source type */
		       XmRXmString,	/* target type */
		       _XmCvtStringToXmString,	/* converter routine */
		       NULL,	/* args for converter routine */
		       0,	/* number of args to converter routine */
		       XtCacheAll,	/* caching instructions */
		       NULL);	/* destructor function */

#ifndef	NO_TRAITS
	if (!XmeTraitSet(xmTextFieldWidgetClass, XmQTaccessTextual, &_XmTextFTraitRec)) {
		DEBUGOUT(XdbDebug(__FILE__, NULL,
			"ClassInitialize: XmeTraitSet failed\n"));
	}
#endif
}

static void
class_part_initialize(WidgetClass widget_class)
{
    DBG("class_part_initialize");

    _XmFastSubclassInit(widget_class, XmTEXT_FIELD_BIT);
}

static void
initialize(Widget request, Widget tnew, ArgList args, Cardinal *num)
{
    XmTextFieldWidget w = (XmTextFieldWidget)tnew;

    DBGW("initialize");

    /* deal with the translations -- someone tell me if this is wrong... */
#if 1
    XtAugmentTranslations((Widget)w,
			  XtParseTranslationTable(_XmTextF_EventBindings2));

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

    w->text.extension =
	(XtPointer)XtMalloc(sizeof(XmTextFieldPartLesstifExtension));

    /* set up the initial text string */
    TextF_SelectionText(w) = NULL;
    TextF_TextWidth(w) = TextF_OldTextWidth(w) = 0;

    if (TextF_Value(w) != (char *)XmUNSPECIFIED)
    {
	char *temp;

	TextF_Length(w) = strlen(TextF_Value(w));
	TextF_Alloc(w) = TextF_Length(w) + TF_ALLOC_SIZE;

	temp = (char *)XtMalloc(TextF_Alloc(w));
	strcpy(temp, TextF_Value(w));

	TextF_Value(w) = temp;
    }
    else
    {
	TextF_Alloc(w) = TF_ALLOC_SIZE;

	TextF_Value(w) = (char *)XtMalloc(TextF_Alloc(w));

	TextF_Length(w) = 0;
    }

    /* Get the font information */
    FontInitialize(w);

    if (XtWidth(request) == (Dimension)0)
    {				/* the user didn't say how wide */
#ifdef	USE_AVERAGE_WIDTH
	XtWidth(w) = (2 * Prim_ShadowThickness(w) +
		      2 * Prim_HighlightThickness(w) +
		      2 * TextF_MarginWidth(w) +
		      TextF_Columns(w) * TextF_FontAverageWidth(w));
#else
	XtWidth(w) = (2 * Prim_ShadowThickness(w) +
		      2 * Prim_HighlightThickness(w) +
		      2 * TextF_MarginWidth(w) +
		      TextF_Columns(w) * TextF_FontMaxWidth(w));
#endif
    }
    /* the user specified a width, so fit the columns to it. */
    else
    {
#ifdef	USE_AVERAGE_WIDTH
	TextF_Columns(w) = (XtWidth(w)
			    - 2 * Prim_ShadowThickness(w)
			    - 2 * TextF_MarginWidth(w)) /
	    TextF_FontAverageWidth(w);
#else
	TextF_Columns(w) = (XtWidth(w)
			    - 2 * Prim_ShadowThickness(w)
			    - 2 * TextF_MarginWidth(w)) /
	    TextF_FontMaxWidth(w);
#endif
    }

    if (XtHeight(request) == (Dimension)0)
    {
	XtHeight(w) = (2 * Prim_ShadowThickness(w) +
		       2 * Prim_HighlightThickness(w) +
		       2 * TextF_MarginHeight(w) +
		       TextF_FontHeight(w));
    }

    SizeRecalc(w);

    /* initialize cursor position */
    if (TextF_CursorPos(w) > 0)
    {
	if (TextF_CursorPos(w) > TextF_Length(w))
	{
	    TextF_CursorPos(w) = TextF_Length(w);
	}
    }
    else
    {
	TextF_CursorPos(w) = 0;
    }

    TextF_OldCursorX(w) = -1;
    TextF_HighlightStart(w) = TextF_HighlightEnd(w) = -1;
    TextF_OldHighlightStart(w) = TextF_OldHighlightEnd(w) = -1;

    TextF_XOffset(w) = TextF_OldXOffset(w) = 0;

    /* initialize booleans */
    TextF_TimerId(w) = (XtIntervalId)0;
    TextF_SelectId(w) = (XtIntervalId)0;

    w->text.last_time = (Time)0;

    w->text.sarray_index = 0;

    TextF_Echo(w) = True;
    TextF_AllowSelection(w) = True;
    TextF_HasFocus(w) = False;

    /* initialize pixmaps and graphics contexts */
    TextF_CursorIBeam(w) = (Pixmap)NULL;
    TextF_CursorStipple(w) = (Pixmap)NULL;
    TextF_CursorSave(w) = (Pixmap)NULL;

    /* Use DrawGC as a flag to see if the GCs have been created */
    TextF_DrawGC(w) = NULL;
}

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

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

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

    GCInitialize(w);
    GCClip(w);

    _XmTextFieldSetEditable(aw, TextF_Editable(w));
}

static void
destroy(Widget aw)
{
    XmTextFieldWidget w = (XmTextFieldWidget)aw;

    DBGW("destroy");

    if (TextF_SelectId(aw))
    {
	XtRemoveTimeOut(TextF_SelectId(aw));
    }

    if (TextF_TimerId(aw))
    {
	XtRemoveTimeOut(TextF_TimerId(aw));
    }

    XtReleaseGC((Widget)w, TextF_DrawGC(w));
    XtReleaseGC((Widget)w, TextF_CursorGC(w));
    XtReleaseGC((Widget)w, TextF_CopyGC(w));

    if (TextF_FontListCreated(w))
    {
	XmFontListFree(TextF_FontList(w));
    }

    if (TextF_SelectionText(w))
    {
	XtFree(TextF_SelectionText(w));
    }

    XtFree(TextF_Value(w));
}

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

    DBGW("expose");

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

    /* Then draw ourselves on top of it */
    DrawAll(w);

    _XmDrawShadows(XtDisplay(w),
		   XtWindow(w),
		   Prim_TopShadowGC(w),
		   Prim_BottomShadowGC(w),
		   Prim_HighlightThickness(w), Prim_HighlightThickness(w),
		   XtWidth(w) - 2 * Prim_HighlightThickness(w),
		   XtHeight(w) - 2 * Prim_HighlightThickness(w),
		   Prim_ShadowThickness(w),
		   XmSHADOW_IN);
}

static void
resize(Widget aw)
{
    XmTextFieldWidget w = (XmTextFieldWidget)aw;

    DEBUGOUT(XdbDebug(__FILE__, aw,
		      "resize => wid %d ht %d\n", XtWidth(aw), XtHeight(aw)));

    SizeRecalc(w);

    /* Only adjust the GCs if they have already been created! */
    if (TextF_DrawGC(w))
    {
	GCClip(w);
    }

    if (XtIsRealized(aw))
    {
	MassiveChangeDraw(w);
    }
}

static Boolean
set_values(Widget current, Widget request, Widget reply,
	   ArgList args, Cardinal *nargs)
{
    XmTextFieldWidget w = (XmTextFieldWidget)current;
    XmTextFieldWidget new_w = (XmTextFieldWidget)reply;
    Boolean redraw = False;

    DBGW("set_values");

    if (Prim_Foreground(w) != Prim_Foreground(new_w) ||
	XtBackground(w) != XtBackground(new_w))
    {
	XtReleaseGC((Widget)w, TextF_DrawGC(w));
	XtReleaseGC((Widget)w, TextF_CursorGC(w));
	XtReleaseGC((Widget)w, TextF_CopyGC(w));

	GCInitialize(new_w);

	redraw = True;
    }

    if ((TextF_CursorPos(w) != TextF_CursorPos(new_w)) ||
	(TextF_CursorPositionVisible(w) != TextF_CursorPositionVisible(new_w)))
    {
	redraw = True;
    }
    if (TextF_Value(w) != TextF_Value(new_w))
    {
	char *temp;

	redraw = True;

	/* save ptr to the new string */
	temp = TextF_Value(new_w);

	/* need to get old address for malloc */
	TextF_Value(new_w) = TextF_Value(w);

	/* XtRealloc is called here on TextF_Value(new_w) */
	TextSet(new_w, temp);

	TextF_HighlightStart(w) = TextF_HighlightEnd(w) = -1;

	TextF_CursorPos(new_w) = 0;

	DEBUGOUT(XdbDebug(__FILE__, reply,
			  "set_values: %s\n", TextF_Value(new_w)));
    }

    if (TextF_Editable(new_w) != TextF_Editable(new_w))
    {
	_XmTextFieldSetEditable((Widget)new_w, TextF_Editable(new_w));
	redraw = True;
    }

    if (TextF_Columns(w) != TextF_Columns(new_w))
    {
#ifdef	USE_AVERAGE_WIDTH
	XtWidth(new_w) = (2 * Prim_ShadowThickness(new_w) +
			  2 * Prim_HighlightThickness(new_w) +
			  2 * TextF_MarginWidth(new_w) +
			  TextF_Columns(new_w) * TextF_FontAverageWidth(new_w));
#else
	XtWidth(new_w) = (2 * Prim_ShadowThickness(new_w) +
			  2 * Prim_HighlightThickness(new_w) +
			  2 * TextF_MarginWidth(new_w) +
			  TextF_Columns(new_w) * TextF_FontMaxWidth(new_w));
#endif
    }

    return redraw;
}

static XtGeometryResult
query_geometry(Widget aw, XtWidgetGeometry *proposed, XtWidgetGeometry *answer)
{
    XmTextFieldWidget w = (XmTextFieldWidget)aw;
    XtWidgetGeometry a;

#define Wants(x)   (proposed->request_mode & x)

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

	    DEBUGOUT(XdbDebug(__FILE__, aw,
			      "query_geometry: request %s => YES\n",
			      XdbWidgetGeometry2String(proposed)));

	    return XtGeometryYes;
	}
    }

#ifdef	USE_AVERAGE_WIDTH
    /* The code below (in #else) uses MAXIMUM values for the font size, where
     * everything else in this source uses the font's average character width.
     * Make it conform ...
     *
     * Danny 31/10/96
     */
    a.request_mode = CWWidth | CWHeight;
    a.width = (2 * Prim_ShadowThickness(w) + 2 * Prim_HighlightThickness(w) +
	       2 * TextF_MarginWidth(w) +
	       TextF_Columns(w) * TextF_FontAverageWidth(w));

    a.height = (2 * Prim_ShadowThickness(w) + 2 * Prim_HighlightThickness(w) +
		2 * TextF_MarginHeight(w) +
	 TextF_Font(w)->max_bounds.ascent + TextF_Font(w)->max_bounds.descent);
#else
    a.request_mode = CWWidth | CWHeight;
    a.width = (2 * Prim_ShadowThickness(w) + 2 * Prim_HighlightThickness(w) +
	       2 * TextF_MarginWidth(w) +
	       TextF_Columns(w) * TextF_FontMaxWidth(w));

    a.height = (2 * Prim_ShadowThickness(w) + 2 * Prim_HighlightThickness(w) +
		2 * TextF_MarginHeight(w) +
		TextF_Font(w)->max_bounds.ascent +
		TextF_Font(w)->max_bounds.descent);
#endif

    if (answer)
    {
	*answer = a;
    }

    if (proposed->request_mode == 0)
    {				/* NULL proposed -> return Width+Height */
	DEBUGOUT(XdbDebug(__FILE__, aw,
			  "query_geometry: request %s => %s ALMOST\n",
			  XdbWidgetGeometry2String(proposed),
			  XdbWidgetGeometry2String(&a)));

	return XtGeometryAlmost;
    }

    if (proposed->width >= answer->width && proposed->height >= answer->height)
    {
	DEBUGOUT(XdbDebug(__FILE__, aw,
			  "query_geometry: request %s => YES\n",
			  XdbWidgetGeometry2String(proposed)));

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

	DEBUGOUT(XdbDebug(__FILE__, aw,
			  "query_geometry: request %s => %s NO\n",
			  XdbWidgetGeometry2String(proposed),
			  XdbWidgetGeometry2String(&a)));

	return XtGeometryNo;
    }
    else
    {
	DEBUGOUT(XdbDebug(__FILE__, aw,
			  "query_geometry: request %s => %s ALMOST\n",
			  XdbWidgetGeometry2String(proposed),
			  XdbWidgetGeometry2String(&a)));

	return XtGeometryAlmost;
    }
}



/*
 * String manipulation procedures ---------------------------------------------
 */

static void
TextSet(XmTextFieldWidget w, char *s)
{
    int len;

    if (s)
    {
	len = strlen(s);
	if (len > TextF_Alloc(w))
	{
	    TextF_Alloc(w) += len;
	    TextF_Value(w) = XtRealloc(TextF_Value(w), TextF_Alloc(w));
	}

	strcpy(TextF_Value(w), s);

	TextF_Length(w) = len;
	TextF_TextWidth(w) = TextF_OldTextWidth(w) =
	    TextF_FontTextWidth(w, TextF_Value(w), TextF_Length(w));

	if ((TextF_MaxLength(w) > 0) && (TextF_Length(w) > TextF_MaxLength(w)))
	{
	    TextF_MaxLength(w) = TextF_Length(w);
	}
    }
}

static void
TextDelete(XmTextFieldWidget w, int start, int len)
{
    int i;

    if (len > 0)
    {
	for (i = start + len; i < TextF_Length(w); i++)
	{
	    TextF_Value(w)[i - len] = TextF_Value(w)[i];
	}

	TextF_Length(w) -= len;
	TextF_TextWidth(w) = TextF_FontTextWidth(w, TextF_Value(w),
						 TextF_Length(w));
	TextF_Value(w)[TextF_Length(w)] = 0;
    }
}

static void
TextDeleteHighlighted(XmTextFieldWidget w)
{
    if (TextF_HighlightStart(w) >= 0)
    {
	TextDelete(w, TextF_HighlightStart(w),
		   TextF_HighlightEnd(w) - TextF_HighlightStart(w));

	TextF_CursorPos(w) = TextF_HighlightStart(w);
	TextF_HighlightStart(w) = TextF_HighlightEnd(w) = -1;
    }
}

/* returns value indicating if the text can be redrawn using the fast
 * method */
static Boolean
TextInsert(XmTextFieldWidget w, char *buf, int len)
{
    int i;
    Boolean fast_insert;

    fast_insert = True;
    if (len > 0)
    {
	if (TextF_Length(w) + len > TextF_MaxLength(w))
	{
	    VerifyBell(w);
	    fast_insert = False;
	}
	else
	{
	    if (TextF_HighlightStart(w) >= 0)
	    {
		fast_insert = False;
		if (TextF_PendingDelete(w))
		{
		    TextDeleteHighlighted(w);
		}
		else
		{
		    ClearHighlight(w);
		}
	    }

	    if (TextF_Length(w) + len > TextF_Alloc(w))
	    {
		i = TF_ALLOC_SIZE;
		if (i < len)
		    i = len;
		TextF_Alloc(w) += i + 1;
		TextF_Value(w) = XtRealloc(TextF_Value(w), TextF_Alloc(w));

		DBG1("TextInsert: Alloced new space\n", TextF_Alloc(w));
	    }

	    for (i = TextF_Length(w) - 1; i >= TextF_CursorPos(w); i--)
	    {
		TextF_Value(w)[i + len] = TextF_Value(w)[i];
	    }

	    strncpy(&TextF_Value(w)[TextF_CursorPos(w)], buf, len);

	    TextF_FastInsertCursorStart(w) = TextF_CursorPos(w);
	    TextF_FastInsertTextLen(w) = len;
	    TextF_Length(w) += len;

	    TextF_TextWidth(w) = TextF_FontTextWidth(w, TextF_Value(w),
						     TextF_Length(w));
	    TextF_Value(w)[TextF_Length(w)] = 0;
	}
    }

    return fast_insert;
}

static XmTextPosition
TextPixelToSelectionPos(XmTextFieldWidget w, int x)
{
    XmTextPosition i, tot, cur, pos;

    pos = 0;

    x -= (int)TextF_XDraw(w) + TextF_XOffset(w);

    /* check if the cursor is before the 1st character */
    if (x <= 0)
    {
	pos = 0;
    }

    /* OK, how 'bout after the last character */
    else if (x > TextF_FontTextWidth(w, TextF_Value(w), TextF_Length(w)))
    {
	pos = TextF_Length(w);
    }

    /* must be in between somewhere... */
    else
    {
	tot = 0;
	pos = -1;
	for (i = 0; i < TextF_Length(w); i++)
	{
	    cur = TextF_FontTextWidth(w, &TextF_Value(w)[i], 1);
	    if (x < tot + (cur / 2))
	    {
		pos = i;
		break;
	    }
	    tot += cur;
	}
	if (pos < 0)
	{
	    pos = TextF_Length(w);
	}

    }
    return pos;
}

static XmTextPosition
TextPixelToPos(XmTextFieldWidget w, int x)
{
    XmTextPosition i, tot, cur, pos;

    pos = 0;

    x -= (int)TextF_XDraw(w) + TextF_XOffset(w);

    /* check if the cursor is before the 1st character */
    if (x <= 0)
    {
	pos = 0;
    }

    /* OK, how 'bout after the last character */
    else if (x > TextF_FontTextWidth(w, TextF_Value(w), TextF_Length(w)))
    {
	pos = TextF_Length(w);
    }
    /* must be in between somewhere... */
    else
    {
	tot = 0;
	pos = -1;
	for (i = 0; i < TextF_Length(w); i++)
	{
	    cur = TextF_FontTextWidth(w, &TextF_Value(w)[i], 1);
	    if (x < tot + cur)
	    {
		pos = i;
		break;
	    }
	    tot += cur;
	}
	if (pos < 0)
	{
	    pos = TextF_Length(w);
	}
    }
    return pos;
}


/*
 * Private drawing functions --------------------------------------------------
 */

static Boolean
MakePositionVisible(XmTextFieldWidget w, XmTextPosition pos)
{
    int x, start, end;
    Boolean moved;

    moved = False;
    x = TextF_FontTextWidth(w, TextF_Value(w), pos);
    start = -TextF_XOffset(w);
    end = start + TextF_ViewWidth(w);

    if (x < start)
    {
	TextF_XOffset(w) = -x;
	moved = True;
    }
    else if (x > end)
    {
	TextF_XOffset(w) = TextF_ViewWidth(w) - x;
	moved = True;
    }

    if (XdbInDebug(__FILE__, (Widget)w))
    {
	DEBUGOUT(XdbDebug(__FILE__, (Widget)w,
			"MakePositionVisible: start=%d end=%d x=%d moved=%d\n",
			  start, end, x, (int)moved));
    }

    return moved;
}

/*
 * Actually draw a range of text onto the widget
 */
static void
DrawText(XmTextFieldWidget w, int start, int end, Boolean highlight)
{
    int x;

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

    if (TextF_Length(w) > 0)
    {
	if (start < 0)
	{
	    return;
	}
	else if (end < start)
	{
	    int temp;

	    temp = start;
	    start = end;
	    end = temp;
	}

	if (start > TextF_Length(w))
	{
	    return;
	}
	else if (end > TextF_Length(w))
	{
	    end = TextF_Length(w);
	}

	x = TextF_XDraw(w) + TextF_XOffset(w) +
	    TextF_FontTextWidth(w, TextF_Value(w), start);

	if (highlight && !TextF_DrawGCInverted(w))
	{
	    XSetForeground(XtDisplay(w), TextF_DrawGC(w), XtBackground(w));
	    XSetBackground(XtDisplay(w), TextF_DrawGC(w), Prim_Foreground(w));

	    TextF_DrawGCInverted(w) = True;
	}
	else if (!highlight && TextF_DrawGCInverted(w))
	{
	    XSetForeground(XtDisplay(w), TextF_DrawGC(w), Prim_Foreground(w));
	    XSetBackground(XtDisplay(w), TextF_DrawGC(w), XtBackground(w));

	    TextF_DrawGCInverted(w) = False;
	}
	if ((end - start) > 0)
	{
	    XDrawImageString(XtDisplay(w), XtWindow(w), TextF_DrawGC(w),
			     x, TextF_YOffset(w),
			     &TextF_Value(w)[start], end - start);
	}
    }
}

static void
DrawTextRange(XmTextFieldWidget w, int start, int end)
{
    if (!TextF_Echo(w))
    {
	return;
    }

    if (TextF_Length(w) > 0)
    {
	if (start < 0)
	{
	    return;
	}
	else if (end < start)
	{
	    int temp;

	    temp = start;
	    start = end;
	    end = temp;
	}

	/* If there is no highlighting, or the refresh area doesn't cross the
	 * the highlight borders, just redraw it. */
	if (TextF_HighlightStart(w) < 0 ||
	    start >= TextF_HighlightEnd(w) ||
	    end <= TextF_HighlightStart(w))
	{
	    DrawText(w, start, end, False);
	}
	/* OK, the refresh area crosses one or both highlight borders. */
	else
	{
	    int clip;

	    while (start < end)
	    {
		if (start < TextF_HighlightStart(w))
		{
		    if (end <= TextF_HighlightStart(w))
		    {
			clip = end;
		    }
		    else
		    {
			clip = TextF_HighlightStart(w);
		    }

		    DrawText(w, start, clip, False);

		    start = clip;
		}
		else if (start < TextF_HighlightEnd(w))
		{
		    if (end <= TextF_HighlightEnd(w))
		    {
			clip = end;
		    }
		    else
		    {
			clip = TextF_HighlightEnd(w);
		    }

		    DrawText(w, start, clip, True);

		    start = clip;
		}
		else
		{
		    DrawText(w, start, end, False);

		    start = end;
		}
	    }
	}
    }
}

static void
DrawTextReposition(XmTextFieldWidget w)
{
    int xsrc, xdest, width, start, end;

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

    if (TextF_XOffset(w) < TextF_OldXOffset(w))
    {
	xsrc = TextF_OldXOffset(w) - TextF_XOffset(w);
	xdest = 0;
	width = TextF_ViewWidth(w) - xsrc + 1;

	/* Need to redraw some characters at the end. */
	end = TextPixelToPos(w, TextF_XDraw(w) + TextF_ViewWidth(w));
	start = TextPixelToPos(w, TextF_XDraw(w) + TextF_ViewWidth(w) - xsrc);
    }
    else if (TextF_XOffset(w) > TextF_OldXOffset(w))
    {
	xsrc = 0;
	xdest = TextF_XOffset(w) - TextF_OldXOffset(w);
	width = TextF_ViewWidth(w) - xdest + 1;

	/* Need to redraw some characters at the beginning. */

	start = TextPixelToPos(w, TextF_XDraw(w));
	end = TextPixelToPos(w, TextF_XDraw(w) + xdest);
    }
    else
    {
	return;
    }

    if (width > 0)
    {
	if (XdbInDebug(__FILE__, (Widget)w))
	{
	    DEBUGOUT(XdbDebug(__FILE__, (Widget)w,
			      "Reposition: xoff=%d old=%d src=%d dest=%d"
			      " width=%d refresh %d-%d\n",
			    TextF_XOffset(w), TextF_OldXOffset(w), xsrc, xdest,
			      width, start, end));
	}

	XCopyArea(XtDisplay(w), XtWindow(w), XtWindow(w),
		  TextF_DrawGC(w),
		  TextF_XDraw(w) + xsrc, TextF_YDraw(w),
		  (unsigned int)width, (unsigned int)TextF_ViewHeight(w),
		  TextF_XDraw(w) + xdest, TextF_YDraw(w));

	/*
	 * Erase to the end of the window (if necessary).  This removes any
	 * garbage that might be left over from the XCopyArea
	 */
	if (xdest < xsrc)
	{
	    XClearArea(XtDisplay(w), XtWindow(w),
		       TextF_XDraw(w) + xdest + width, TextF_YDraw(w),
		       xsrc - xdest, (unsigned int)TextF_ViewHeight(w),
		       False);

	    if (XdbInDebug(__FILE__, (Widget)w))
	    {
		DEBUGOUT(XdbDebug(__FILE__, (Widget)w,
				  "Reposition: erasing x=%d y=%d w=%d h=%d\n",
				TextF_XDraw(w) + xdest + width, TextF_YDraw(w),
			     xsrc - xdest, (unsigned int)TextF_ViewHeight(w)));
	    }

	}

	if (start == end)
	{
	    end++;
	}

	DrawTextRange(w, start, end);
    }
    else
    {
	/* redraw the entire visible string */
	start = TextPixelToPos(w, TextF_XDraw(w));
	end = TextPixelToPos(w, TextF_XDraw(w) + TextF_ViewWidth(w)) + 1;

	DrawTextRange(w, start, end);

	if (XdbInDebug(__FILE__, (Widget)w))
	{
	    DEBUGOUT(XdbDebug(__FILE__, (Widget)w,
			      "Reposition: xoff=%d old=%d refresh %d-%d\n",
			   TextF_XOffset(w), TextF_OldXOffset(w), start, end));
	}

    }

    TextF_OldXOffset(w) = TextF_XOffset(w);
}

static void
EraseXRange(XmTextFieldWidget w, int start, int end)
{
    int x1, x2;

    x1 = TextF_XOffset(w) + start;
    x2 = TextF_XOffset(w) + end;
    if (x1 < 0)
    {
	x1 = 0;
    }
    if (x2 > TextF_ViewWidth(w))
    {
	x2 = TextF_ViewWidth(w);
    }
    if (x2 > x1)
    {
	XClearArea(XtDisplay(w), XtWindow(w),
		   TextF_XDraw(w) + x1, TextF_YDraw(w),
		   x2 - x1 + 1,
		   TextF_ViewHeight(w), False);
    }
}

static void
DrawTextWithCopyArea(XmTextFieldWidget w)
{
    int x, insert_width;
    int xsrc, xdest, width;

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

    x = TextF_XOffset(w);
    insert_width = TextF_FontTextWidth(w,
			       &TextF_Value(w)[TextF_FastInsertCursorStart(w)],
				       TextF_FastInsertTextLen(w));

    if (CursorPosition(w))
    {
	/*
	 *  if the text is scrolled, then:
	 * 1.  the cursor is at the end
	 * 2.  the copy will move to the left.
	 */
	xsrc = 0;
	width = TextF_OldCursorX(w) + x;
	xdest = TextF_ViewWidth(w) - (x + TextF_OldCursorX(w)) - insert_width;

	XCopyArea(XtDisplay(w), XtWindow(w), XtWindow(w),
		  TextF_DrawGC(w),
		  TextF_XDraw(w) + xsrc, TextF_YDraw(w),
		  (unsigned int)width, (unsigned int)TextF_ViewHeight(w),
		  TextF_XDraw(w) + xdest, TextF_YDraw(w));

	if (XdbInDebug(__FILE__, (Widget)w))
	{
	    DEBUGOUT(XdbDebug(__FILE__, (Widget)w,
			      "DrawTextWCA: x=%d xsrc=%d xdest=%d width=%d\n",
			      x, xsrc, xdest, width));
	}

    }
    else
    {
	/*
	 * the text hasn't been scrolled, so:
	 * 1.  the text left of the cursor won't change
	 * 2.  the stuff after the cursor will be moved right.
	 */
	xsrc = TextF_FontTextWidth(w,
				   TextF_Value(w),
				   TextF_FastInsertCursorStart(w)) + x;

	width = TextF_ViewWidth(w) - xsrc;
	xdest = xsrc + insert_width;

	XCopyArea(XtDisplay(w), XtWindow(w), XtWindow(w),
		  TextF_DrawGC(w),
		  TextF_XDraw(w) + xsrc, TextF_YDraw(w),
		  (unsigned int)width, (unsigned int)TextF_ViewHeight(w),
		  TextF_XDraw(w) + xdest, TextF_YDraw(w));

	if (XdbInDebug(__FILE__, (Widget)w))
	{
	    DEBUGOUT(XdbDebug(__FILE__, (Widget)w,
			      "DrawTextWCA: x=%d xsrc=%d xdest=%d width=%d\n",
			      x, xsrc, xdest, width));
	}
    }

    DrawTextRange(w, TextF_FastInsertCursorStart(w),
		  TextF_FastInsertCursorStart(w) + TextF_FastInsertTextLen(w));

    if (TextF_TextWidth(w) < TextF_OldTextWidth(w))
    {
	EraseXRange(w, TextF_TextWidth(w), TextF_OldTextWidth(w));
    }

    TextF_OldTextWidth(w) = TextF_TextWidth(w);
    TextF_OldXOffset(w) = TextF_XOffset(w);
}

static void
DrawAllText(XmTextFieldWidget w)
{
    if (!TextF_Echo(w))
    {
	return;
    }

    DrawTextRange(w, 0, TextF_Length(w));

    if (TextF_TextWidth(w) < TextF_OldTextWidth(w))
    {
	EraseXRange(w, TextF_TextWidth(w), TextF_OldTextWidth(w));
    }

    TextF_OldTextWidth(w) = TextF_TextWidth(w);
    TextF_OldXOffset(w) = TextF_XOffset(w);
    TextF_OldHighlightStart(w) = TextF_HighlightStart(w);
    TextF_OldHighlightEnd(w) = TextF_HighlightEnd(w);
}


/* Cursor functions -------------------------------------------------------- */

static Boolean
CursorPosition(XmTextFieldWidget w)
{
    if (TextF_CursorPos(w) < 0)
    {
	TextF_CursorPos(w) = 0;
    }
    else if (TextF_CursorPos(w) > TextF_Length(w))
    {
	TextF_CursorPos(w) = TextF_Length(w);
    }

    return MakePositionVisible(w, TextF_CursorPos(w));
}

static Boolean
CursorMassiveAdjust(XmTextFieldWidget w)
{
    int start, end, last;
    Boolean moved;

    moved = False;
    end = TextF_FontTextWidth(w, TextF_Value(w), TextF_CursorPos(w));

    if (TextF_HighlightStart(w) >= 0)
    {
	start = TextF_FontTextWidth(w, TextF_Value(w), TextF_HighlightStart(w));
    }
    else
    {
	start = end;
    }

    if (end < TextF_ViewWidth(w))
    {
	if (TextF_XOffset(w) < 0)
	{
	    TextF_XOffset(w) = 0;
	    moved = True;
	}
    }
    else if (start >= TextF_XOffset(w) &&
	     end < TextF_XOffset(w) + TextF_ViewWidth(w))
    {
	return moved;
    }
    else
    {
	last = TextF_FontTextWidth(w, TextF_Value(w), TextF_Length(w));
	if (start - end > TextF_ViewWidth(w))
	{
	    if (last - end > TextF_ViewWidth(w))
	    {
		TextF_XOffset(w) = TextF_ViewWidth(w) - last;
	    }
	    else
	    {
		TextF_XOffset(w) = TextF_ViewWidth(w) - end;
	    }
	}
	else if (end > TextF_ViewWidth(w))
	{
	    TextF_XOffset(w) = TextF_ViewWidth(w) - end;
	}
	else
	{
	    TextF_XOffset(w) = 0;
	}
	moved = True;
    }

    return moved;
}

static void
CursorSet(XmTextFieldWidget w, Boolean focus)
{
    TextF_HasFocus(w) = focus;

/* These change the GC !! (Danny) */
    if (focus)
    {
	XSetStipple(XtDisplay((Widget)w),
		    TextF_CursorGC(w),
		    TextF_CursorIBeam(w));
    }
    else
    {
	XSetStipple(XtDisplay((Widget)w),
		    TextF_CursorGC(w),
		    TextF_CursorStipple(w));
    }
}

static void
CursorSaveUnderIBeam(XmTextFieldWidget w, int x)
{
    if (!XtIsRealized((Widget)w))
    {
	return;
    }

    /* Make sure that the text is drawn before saving the cursor */
    XFlush(XtDisplay((Widget)w));

    /* save the area under the cursor */
    XFillRectangle(XtDisplay((Widget)w), TextF_CursorSave(w), TextF_CopyGC(w),
		   0, 0, 5, TextF_ViewHeight(w));

    XCopyArea(XtDisplay((Widget)w), XtWindow((Widget)w), TextF_CursorSave(w),
	      TextF_CursorGC(w),
	      x - 2, TextF_YDraw(w),
	      5, TextF_ViewHeight(w), 0, 0);

    TextF_CursorSaveValid(w) = True;
}

static void
CursorRestoreUnderIBeam(XmTextFieldWidget w)
{
    int x;

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

    /* Make sure that the text is drawn before erasing the cursor */
    XFlush(XtDisplay((Widget)w));

    x = TextF_OldCursorX(w) + TextF_XDraw(w) + TextF_XOffset(w);

    XCopyArea(XtDisplay((Widget)w), TextF_CursorSave(w), XtWindow((Widget)w),
	      TextF_CursorGC(w), 0, 0, 5, TextF_ViewHeight(w),
	      x - 2, TextF_YDraw(w));

    TextF_CursorSaveValid(w) = False;
}


static void
CursorDrawIBeam(XmTextFieldWidget w, int x)
{
    /* save the area under the cursor */
    CursorSaveUnderIBeam(w, x);

    /* These change the GC !! (Danny) */
    XSetTSOrigin(XtDisplay((Widget)w), TextF_CursorGC(w),
		 x - 2, TextF_YOffset(w) - TextF_FontAscent(w) + 1);

    XFillRectangle(XtDisplay((Widget)w), XtWindow((Widget)w), TextF_CursorGC(w),
		   x - 2, TextF_YDraw(w), 5, TextF_ViewHeight(w));
}

static void
CursorDraw(XmTextFieldWidget w)
{
    int x;

    if (TextF_CursorPositionVisible(w))
    {
	x = TextF_FontTextWidth(w, TextF_Value(w), TextF_CursorPos(w));

	TextF_OldCursorPos(w) = TextF_CursorPos(w);
	TextF_OldCursorX(w) = x;

	x += TextF_XDraw(w) + TextF_XOffset(w);

	CursorDrawIBeam(w, x);

	TextF_BlinkOn(w) = True;
    }
}

static void
CursorErase(XmTextFieldWidget w)
{
    if (TextF_CursorSaveValid(w))
    {
	CursorRestoreUnderIBeam(w);
    }

    TextF_BlinkOn(w) = False;
}

static void
ClearHighlight(XmTextFieldWidget w)
{
    if (!TextF_Echo(w))
	return;

    if (TextF_HighlightStart(w) >= 0)
    {
	CursorErase(w);
	DrawText(w, TextF_HighlightStart(w), TextF_HighlightEnd(w), False);
	CursorDraw(w);
	TextF_HighlightStart(w) = TextF_HighlightEnd(w) = -1;
    }

    TextF_OldHighlightStart(w) = TextF_OldHighlightEnd(w) = -1;
}

static void
DrawHighlight(XmTextFieldWidget w)
{
    if (!TextF_Echo(w))
    {
	return;
    }

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

    if (TextF_OldHighlightStart(w) < 0)
    {
	DrawText(w, TextF_HighlightStart(w), TextF_HighlightEnd(w),
		 True);
    }
    else
    {
	DrawText(w, TextF_HighlightStart(w), TextF_OldHighlightStart(w),
		 (TextF_HighlightStart(w) < TextF_OldHighlightStart(w)));

	DrawText(w, TextF_HighlightEnd(w), TextF_OldHighlightEnd(w),
		 (TextF_HighlightEnd(w) > TextF_OldHighlightEnd(w)));
    }

    TextF_OldHighlightStart(w) = TextF_HighlightStart(w);
    TextF_OldHighlightEnd(w) = TextF_HighlightEnd(w);
}

/*
 * Special redraw function after a text insertion
 */
static void
DrawInsert(XmTextFieldWidget w)
{
    if (!XtIsRealized(w))
    {
	return;
    }

    /*  CursorErase must be called before this */
    DrawTextWithCopyArea(w);
    CursorDraw(w);
}

/*
 * Special redraw function after a cursor reposition (i.e.: no text changes)
 */
static void
DrawMove(XmTextFieldWidget w)
{
    if (!XtIsRealized(w))
    {
	return;
    }

    CursorErase(w);
    if (CursorPosition(w))
    {
	DrawTextReposition(w);
    }

    CursorDraw(w);
}

/*
 * Redraw the entire widget, but don't scroll the window much
 */
static void
Draw(XmTextFieldWidget w)
{
    if (!XtIsRealized(w))
    {
	return;
    }

    CursorErase(w);

    CursorPosition(w);

    DrawAllText(w);

    CursorDraw(w);
}

/*
 * Clear window & redraw the entire widget
 */
static void
DrawAll(XmTextFieldWidget w)
{
    if (!XtIsRealized(w))
    {
	return;
    }

    XClearArea(XtDisplay(w), XtWindow(w),
	       Prim_HighlightThickness(w),
	       Prim_HighlightThickness(w),
	       XtWidth(w) - 2 * Prim_HighlightThickness(w),
	       XtHeight(w) - 2 * Prim_HighlightThickness(w),
	       False);

    CursorPosition(w);

    DrawAllText(w);

    CursorDraw(w);
}

/*
 * Like Draw(), but has different rules about scrolling the window to
 * put the cursor in a good place
 */
static void
MassiveChangeDraw(XmTextFieldWidget w)
{
    if (!XtIsRealized(w))
    {
	return;
    }

    CursorErase(w);

    CursorMassiveAdjust(w);

    DrawAllText(w);

    CursorDraw(w);
}



/*
 * text search procedures -----------------------------------------------------
 */

static Boolean
InWord(char s)
{
    switch (s)
    {
    case ' ':
    case '\t':
    case '\n':
    case '!':
    case '?':
    /* rws 17 Aug 1997
       I do not think this should be included. Double clicking on a word
       that has a '.' in it will include the '.' in Motif.
     */
    /* case '.':*/
    case ',':
	return False;

    default:
	return True;
    }
}

static XmTextPosition
WordEnd(XmTextFieldWidget w, XmTextPosition pos)
{
    while ((pos < TextF_Length(w)) && InWord(TextF_Value(w)[pos]))
    {
	pos++;
    }

    return pos;
}

static XmTextPosition
WordStart(XmTextFieldWidget w, XmTextPosition pos)
{
    while ((pos > 0) && InWord(TextF_Value(w)[pos - 1]))
    {
	pos--;
    }

    return pos;
}

static XmTextPosition
SkipForward(XmTextFieldWidget w, XmTextPosition pos)
{
    while ((pos < TextF_Length(w)) && !InWord(TextF_Value(w)[pos]))
    {
	pos++;
    }

    return pos;
}

static XmTextPosition
SkipBackward(XmTextFieldWidget w, XmTextPosition pos)
{
    while ((pos > 0) && !InWord(TextF_Value(w)[pos - 1]))
    {
	pos--;
    }

    return pos;
}

static XmTextScanType
ScanType(XmTextFieldWidget w)
{
    XmTextScanType type;

    if (TextF_SelectionArray(w))
    {
	if (w->text.sarray_index >= TextF_SelectionArrayCount(w))
	{
	    w->text.sarray_index = 0;
	}

	type = TextF_SelectionArray(w)[w->text.sarray_index];
    }
    else
    {
	switch (w->text.sarray_index)
	{
	case 1:
	    type = XmSELECT_WORD;
	    break;

	case 2:
	    type = XmSELECT_ALL;
	    break;

	default:
	    type = XmSELECT_POSITION;
	    w->text.sarray_index = 0;
	    break;
	}
    }

    return type;
}

static XmTextPosition
ScanTypeStart(XmTextFieldWidget w, XmTextPosition pos)
{
    switch (ScanType(w))
    {
    case XmSELECT_WORD:
	pos = WordStart(w, pos);
	break;

    case XmSELECT_WHITESPACE:
	pos = SkipBackward(w, pos);
	break;

    case XmSELECT_LINE:
    case XmSELECT_PARAGRAPH:
    case XmSELECT_ALL:
	pos = 0;
	break;

    case XmSELECT_POSITION:
    default:
	break;
    }

    return pos;
}

static XmTextPosition
ScanTypeEnd(XmTextFieldWidget w, XmTextPosition pos)
{
    switch (ScanType(w))
    {
    case XmSELECT_WORD:
	pos = WordEnd(w, pos);
	break;

    case XmSELECT_WHITESPACE:
	pos = SkipForward(w, pos);
	break;

    case XmSELECT_LINE:
    case XmSELECT_PARAGRAPH:
    case XmSELECT_ALL:
	pos = TextF_Length(w);
	break;

    case XmSELECT_POSITION:
    default:
	break;
    }
    return pos;
}


/*
 * High level text insert and delete routines ---------------------------------
 */

static void
VerifyBell(XmTextFieldWidget w)
{
    if (TextF_VerifyBell(w))
    {
	XBell(XtDisplay((Widget)w), 50);
    }
}

static Boolean
DoCursorMove(XmTextFieldWidget w, XEvent *ev,
	     XmTextPosition pos, Boolean highlight, Boolean drawit)
{
    XmTextVerifyCallbackStruct cbs;

    if (pos > TextF_Length(w))
    {
	pos = TextF_Length(w);
    }

    cbs.doit = True;
    if (TextF_MotionVerifyCallback(w))
    {
	cbs.reason = XmCR_MOVING_INSERT_CURSOR;
	cbs.event = ev;
	cbs.currInsert = TextF_CursorPos(w);
	cbs.newInsert = pos;
	cbs.startPos = cbs.endPos = 0;
	cbs.text = NULL;

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

	if (cbs.doit)
	{
	    pos = cbs.newInsert;
	}
    }

    if (cbs.doit)
    {
	if (highlight)
	{
	    ClearHighlight(w);
	}

	TextF_CursorPos(w) = pos;
	if (drawit)
	{
	    DrawMove(w);
	}
    }
    else
    {
	VerifyBell(w);
    }

    return cbs.doit;
}

static void
DoInsert(XmTextFieldWidget w, XEvent *ev, char *buf, int len)
{
    XmTextVerifyCallbackStruct cbs;
    XmTextBlockRec tb;
    Boolean fastdraw;

    DEBUGOUT(XdbDebug(__FILE__, (Widget)w,
		      "DoInsert(buf '%s' len %d)\n", buf, len));

    if (len <= 0)
    {
	return;
    }

    cbs.doit = True;
    tb.ptr = NULL;
    if (TextF_ModifyVerifyCallback(w))
    {
	cbs.reason = XmCR_MODIFYING_TEXT_VALUE;
	cbs.event = ev;
	cbs.currInsert = cbs.newInsert = TextF_CursorPos(w);
	cbs.startPos = cbs.endPos = TextF_CursorPos(w);

	tb.ptr = XtMalloc(len + 1);	/* NULL-terminate */
	tb.length = len;
	tb.format = XmFMT_8_BIT;
	strncpy(tb.ptr, buf, len);
	tb.ptr[len] = '\0';	/* NULL-terminate */

	cbs.text = &tb;
	XtCallCallbacks((Widget)w, XmNmodifyVerifyCallback, &cbs);

	if (cbs.doit)
	{
	    buf = tb.ptr;
	    len = tb.length;
	}
	else
	{
	    VerifyBell(w);
	}
    }

    if (len > 0 && cbs.doit)
    {
	if (TextF_HighlightStart(w) >= 0)
	{
	    fastdraw = False;
	    if (TextF_PendingDelete(w))
	    {
	        TextDeleteHighlighted(w);
	    }
	}
	if (TextF_Length(w) + len > TextF_MaxLength(w))
	{
	    VerifyBell(w);
	}
	else
	{
	    CursorErase(w);
	    fastdraw = TextInsert(w, buf, len);

	    DoCursorMove(w, ev, TextF_CursorPos(w) + len, True, False);

	    if (fastdraw)
	    {
		DrawInsert(w);
	    }
	    else
	    {
		Draw(w);
	    }

	    if (TextF_ValueChangedCallback(w))
	    {
		cbs.reason = XmCR_VALUE_CHANGED;
		cbs.currInsert = cbs.newInsert = TextF_CursorPos(w);
		cbs.startPos = cbs.endPos = TextF_CursorPos(w);

		if (tb.ptr)
		{
		    tb.ptr = XtMalloc(len);
		    strncpy(tb.ptr, buf, len);
		    XtFree(buf);
		}
		else
		{
		    tb.ptr = XtMalloc(len);
		    strncpy(tb.ptr, buf, len);
		}

		tb.length = len;
		tb.format = XmFMT_8_BIT;

		cbs.text = &tb;

		XtCallCallbacks((Widget)w, XmNvalueChangedCallback, &cbs);
	    }
	}
    }

    if (tb.ptr)
    {
	XtFree(tb.ptr);
    }
}

static void
DoScanType(XmTextFieldWidget w, XEvent *ev, XmTextPosition pos)
{
    switch (ScanType(w))
    {
    case XmSELECT_POSITION:
	DoCursorMove(w, ev, pos, True, True);

	TextF_HighlightPivot(w) = TextF_CursorPos(w);
	break;

    default:
	TextF_HighlightPivot(w) = TextF_HighlightStart(w) =
	    ScanTypeStart(w, pos);
	TextF_HighlightEnd(w) = ScanTypeEnd(w, pos);

	/* FIX ME - what event type should this be? */
	PrimarySelectionComplete(w, ev->xbutton.time);
	Draw(w);
	break;
    }
}



/*
 * Selection and Clipboard utilities ------------------------------------------
 */

static void
ExtendHighlight(XmTextFieldWidget w)
{
    int x, pos;

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

    x = w->text.select_pos_x;

    if (x < (int)TextF_XDraw(w))
    {
	pos = TextPixelToSelectionPos(w, (int)0);
	if (pos > 0)
	{
	    pos--;
	}
    }
    else if (x > (int)(TextF_XDraw(w) + TextF_ViewWidth(w)))
    {
	pos = TextPixelToSelectionPos(w,
				   (int)(TextF_XDraw(w) + TextF_ViewWidth(w)));
	if (pos < TextF_Length(w))
	{
	    pos++;
	}
    }
    else
    {
	pos = TextPixelToSelectionPos(w, x);
    }

    if (pos == TextF_CursorPos(w))
    {
	return;
    }
    DoCursorMove(w, NULL, pos, False, True);

    if (pos < TextF_HighlightPivot(w))
    {
	pos = TextF_HighlightStart(w) = ScanTypeStart(w, pos);

	TextF_HighlightEnd(w) = ScanTypeEnd(w, TextF_HighlightPivot(w));
    }
    else
    {
	TextF_HighlightStart(w) = ScanTypeStart(w, TextF_HighlightPivot(w));

	pos = TextF_HighlightEnd(w) = ScanTypeEnd(w, pos);
    }

    CursorErase(w);

    if (MakePositionVisible(w, pos))
    {
	DrawTextReposition(w);
    }

    DrawHighlight(w);

    CursorDraw(w);
}

static void
ExtendTimer(XtPointer client_data, XtIntervalId *idp)
{
    XmTextFieldWidget w = (XmTextFieldWidget)client_data;
    int highlight_time;

    highlight_time = XtGetMultiClickTime(XtDisplay((Widget)w)) / 2;

    ExtendHighlight(w);

    TextF_SelectId(w) = XtAppAddTimeOut(XtWidgetToApplicationContext((Widget)w),
					(unsigned long)highlight_time,
					ExtendTimer,
					(XtPointer)w);

}

/* #include <X11/Xmu/Xmu.h> */
/* ARGSUSED */
static Boolean
ConvertSelection(Widget aw, Atom *selection, Atom *target, Atom *type,
		 XtPointer *value, unsigned long *length, int *format)
{
    XmTextFieldWidget w = (XmTextFieldWidget)aw;
/*   XSelectionRequestEvent *req = XtGetSelectionRequest(aw, *selection, NULL); */

    /* if (*target == XA_TARGETS(XtDisplay(aw))) { */
/*     Atom *targetP, *std_targets; */
/*     unsigned long std_length; */

/*     XmuConvertStandardSelection(aw, req->time, selection, */
/*       target, type, (XPointer *) & std_targets, */
/*       &std_length, format); */

/*     *value = XtMalloc((unsigned) sizeof(Atom) * (std_length + 1)); */
/*     targetP = *(Atom **) value; */
/*     *length = std_length + 1; */
/*     *targetP++ = XA_STRING; */
/*     bcopy((char *) targetP, (char *) std_targets, sizeof(Atom) * std_length); */
/*     XtFree((char *) std_targets); */
/*     *type = XA_ATOM; */
/*     *format = sizeof(Atom) * 8; */
/*     return True; */
/*   } */
/*   else  */ if (*target == XA_STRING)
    {
	*length = (long)TextF_SelectionLen(w);
	*value = TextF_SelectionText(w);
	*type = XA_STRING;
	*format = 8;
	return True;
    }

    return False;
}

/* ARGSUSED */
static void
LoseSelection(Widget aw, Atom *selection)
{
    XmTextFieldWidget w = (XmTextFieldWidget)aw;

    ClearHighlight(w);
}

/* ARGSUSED */
static void
RequestSelection(Widget aw, XtPointer client, Atom *selection, Atom *type,
		 XtPointer value, unsigned long *length, int *format)
{
    XmTextFieldWidget w = (XmTextFieldWidget)aw;

    if ((!value) || (*length == 0))
    {
	DBGW("RequestSelection: no selection available");
    }
    else
    {
	XEvent *ev;
	XmTextPosition pos;

	ev = (XEvent *)client;
	pos = TextPixelToSelectionPos(w, ev->xbutton.x);

	DBG1("event pos", pos);

	if (XdbInDebug(__FILE__, (Widget)w))
	{
	    DEBUGOUT(XdbDebug(__FILE__, (Widget)w,
		     "RequestSelection: inserting '%s' length=%d at pos: %d\n",
			      (char *)value, (int)(*length), pos));
	}

	if (DoCursorMove(w, ev, pos, True, True))
	{
	    DoInsert(w, ev, (char *)value, (int)(*length));
	}
    }
}

static void
PrimarySelectionComplete(XmTextFieldWidget w, Time time)
{
    int len;

    if (TextF_SelectionText(w))
    {
	XtFree(TextF_SelectionText(w));
    }

    TextF_SelectionText(w) = NULL;
    TextF_SelectionLen(w) = 0;

    len = TextF_HighlightEnd(w) - TextF_HighlightStart(w);
    if (len > 0)
    {
	TextF_SelectionLen(w) = len;
	TextF_SelectionText(w) = XtMalloc(len);
	strncpy(TextF_SelectionText(w),
		&TextF_Value(w)[TextF_HighlightStart(w)],
		len);

	XtOwnSelection((Widget)w, XA_PRIMARY, time,
		       ConvertSelection, LoseSelection, NULL);

#ifdef DEBUG
	XChangeProperty(XtDisplay((Widget)w),
			DefaultRootWindow(XtDisplay((Widget)w)),
			XA_CUT_BUFFER0, XA_STRING, 8, PropModeReplace,
			(unsigned char *)TextF_SelectionText(w), len);
#endif
    }
}



/*
 * Action procedures ----------------------------------------------------------
 */

static void
_BlinkCursorCallback(XtPointer client_data, XtIntervalId *idp)
{
    XmTextFieldWidget w = (XmTextFieldWidget)client_data;

    if (TextF_BlinkOn(w))
    {
	CursorErase(w);
    }
    else
    {
	CursorDraw(w);
    }

    TextF_TimerId(w) = XtAppAddTimeOut(XtWidgetToApplicationContext((Widget)w),
				       TextF_BlinkRate(w),
				       _BlinkCursorCallback,
				       (XtPointer)w);
}


/* the focus in action routine changes the cursor to be filled,
 * and sets it blinking. */
void
_XmTextFieldFocusIn(Widget w, XEvent *event,
		    String *params, Cardinal *num_params)
{
    XmTextVerifyCallbackStruct cbs;
    XmTextFieldWidget tfw = (XmTextFieldWidget)w;

    DBGW("_XmTextFieldFocusIn");

    if (!TextF_HasFocus(tfw))
    {
	CursorErase(tfw);
	CursorSet(tfw, True);

	if (TextF_BlinkRate(tfw) > 0 && !TextF_TimerId(tfw))
	{
	    TextF_TimerId(tfw) = XtAppAddTimeOut(
				     XtWidgetToApplicationContext((Widget)tfw),
						    TextF_BlinkRate(tfw),
						    _BlinkCursorCallback,
						    (XtPointer)tfw);
	}
	else
	{
	    CursorDraw(tfw);
	}

	if (TextF_FocusCallback(tfw))
	{
	    cbs.reason = XmCR_FOCUS;
	    cbs.event = event;
	    cbs.currInsert = cbs.newInsert = TextF_CursorPos(tfw);
	    cbs.startPos = cbs.endPos = 0;
	    cbs.text = NULL;

	    XtCallCallbackList((Widget)tfw, TextF_FocusCallback(tfw), &cbs);
	}

	XtCallActionProc((Widget)tfw, "PrimitiveFocusIn", event,
			 params, *num_params);

    }
}

/* the focus out action routine changes the cursor to be stippled. */
void
_XmTextFieldFocusOut(Widget w, XEvent *event,
		     String *params, Cardinal *num_params)
{
    XmTextVerifyCallbackStruct cbs;
    XmTextFieldWidget tfw = (XmTextFieldWidget)w;

    DBGW("_XmTextFieldFocusOut");

    if (TextF_HasFocus(tfw))
    {
	if (TextF_TimerId(tfw))
	{
	    XtRemoveTimeOut(TextF_TimerId(tfw));
	    TextF_TimerId(tfw) = 0;
	}

	CursorErase(tfw);
	CursorSet(tfw, False);
	CursorDraw(tfw);

	if (TextF_LosingFocusCallback(tfw))
	{
	    cbs.reason = XmCR_LOSING_FOCUS;
	    cbs.event = event;
	    cbs.currInsert = cbs.newInsert = TextF_CursorPos(tfw);
	    cbs.startPos = cbs.endPos = 0;
	    cbs.text = NULL;

	    XtCallCallbackList((Widget)tfw, TextF_LosingFocusCallback(tfw),
			       &cbs);
	}

	XtCallActionProc((Widget)tfw, "PrimitiveFocusOut", event,
			 params, *num_params);
    }
}

static void
activate(Widget w, XEvent *event, String *params, Cardinal *num_params)
{
    XmAnyCallbackStruct cbs;
    Widget parent;

    DBGW("activate");


    cbs.reason = XmCR_ACTIVATE;
    cbs.event = event;

    XtCallCallbackList(w, TextF_ActivateCallback((XmTextFieldWidget)w), &cbs);
/*
   rws 12 Jul 1997
   Pressing return in a TextField that is part of a pre-defined dialog
   should be the same as pressing the OK button in said dialog.
 */
    parent = w;
    while ((parent = XtParent(parent)) != NULL)
    {
	if (XmIsMessageBox(parent) && XmIsDialogShell(XtParent(parent)))
	{
	    /*
	       _XmWarning(w, "This should be pushing the MessageBox OK button of %s (%s:%d)",
	       XtName(parent),__FILE__,__LINE__);
	     */
	    XtCallActionProc(parent,
			     "ManagerParentActivate", NULL, NULL, 0);
	}
    }
}

static void
backward_character(Widget w, XEvent *ev,
		   String *params, Cardinal *num_params)
{
    XmTextFieldWidget tfw = (XmTextFieldWidget)w;
    DBGW("backward_character");

    if (!TextF_Editable(tfw))
    {
	return;
    }

    if (TextF_CursorPos(tfw) > 0)
    {
	XmTextPosition pos;

	pos = TextF_CursorPos(tfw) - 1;

	DoCursorMove(tfw, ev, pos, True, True);
    }
}

static void
backward_word(Widget w, XEvent *ev,
	      String *params, Cardinal *num_params)
{
    XmTextFieldWidget tfw = (XmTextFieldWidget)w;
    DBGW("backward_word");

    if (!TextF_Editable(tfw))
    {
	return;
    }

    if (TextF_CursorPos(tfw) > 0)
    {
	XmTextPosition pos;

	pos = WordStart(tfw, SkipBackward(tfw, TextF_CursorPos(tfw)));

	DoCursorMove(tfw, ev, pos, True, True);
    }
}

static void
beep(Widget w, XEvent *ev,
     String *params, Cardinal *num_params)
{
    DBGW("beep");

    XBell(XtDisplay(w), 50);
}

static void
beginning_of_line(Widget w, XEvent *ev,
		  String *params, Cardinal *num_params)
{
    XmTextFieldWidget tfw = (XmTextFieldWidget)w;

    DBGW("beginning_of_line");

    if (!TextF_Editable(tfw))
    {
	return;
    }

    if (TextF_CursorPos(tfw) > 0)
    {
	XmTextPosition pos;

	pos = 0;

	DoCursorMove(tfw, ev, pos, True, True);
    }
}

static void
clear_selection(Widget w, XEvent *ev,
		String *params, Cardinal *num_params)
{
    XmTextFieldWidget tfw = (XmTextFieldWidget)w;

    DBGW("clear_selection");

    ClearHighlight(tfw);
}

static void
copy_clipboard(Widget w, XEvent *ev,
	       String *params, Cardinal *num_params)
{
    DBGW("copy_clipboard");
}

static void
copy_primary(Widget w, XEvent *ev,
	     String *params, Cardinal *num_params)
{
    DBGW("copy_primary");

    /* paste from the primary into text field at the cursor
     * position */
}

static void
copy_to(Widget w, XEvent *ev,
	String *params, Cardinal *num_params)
{
    XmTextFieldWidget tfw = (XmTextFieldWidget)w;
    DBGW("copy_to");

    if (!TextF_AllowSelection(tfw))
    {
	return;
    }

/*   _XmTextFieldFocusIn(w,ev,params,num_params); */

    XtGetSelectionValue(w, XA_PRIMARY, XA_STRING,
			RequestSelection,
			(XtPointer)ev, ev->xbutton.time);
}

static void
cut_clipboard(Widget w, XEvent *ev,
	      String *params, Cardinal *num_params)
{
    DBGW("cut_clipboard");
}

static void
cut_primary(Widget w, XEvent *ev,
	    String *params, Cardinal *num_params)
{
    DBGW("cut_primary");
}

static void
delete_next_character(Widget w, XEvent *ev,
		      String *params, Cardinal *num_params)
{
    XmTextFieldWidget tfw = (XmTextFieldWidget)w;

    DBGW("delete_next_character");

    if (!TextF_Editable(tfw))
    {
	return;
    }

    if (TextF_HighlightStart(tfw) >= 0 && TextF_PendingDelete(tfw))
    {
	TextDeleteHighlighted(tfw);

	MassiveChangeDraw(tfw);
    }
    else if (TextF_CursorPos(tfw) < TextF_Length(tfw))
    {
	ClearHighlight(tfw);

	TextDelete(tfw, TextF_CursorPos(tfw), 1);

	Draw(tfw);
    }
}

static void
delete_previous_character(Widget w, XEvent *ev,
			  String *params, Cardinal *num_params)
{
    XmTextFieldWidget tfw = (XmTextFieldWidget)w;

    DBGW("delete_previous_character");

    if (!TextF_Editable(tfw))
    {
	return;
    }

    if (TextF_HighlightStart(tfw) >= 0 && TextF_PendingDelete(tfw))
    {
	TextDeleteHighlighted(tfw);

	MassiveChangeDraw(tfw);
    }
    else if (TextF_CursorPos(tfw) > 0)
    {
	ClearHighlight(tfw);

	TextDelete(tfw, TextF_CursorPos(tfw) - 1, 1);

	TextF_CursorPos(tfw)--;

	Draw(tfw);
    }
}

static void
delete_next_word(Widget w, XEvent *ev,
		 String *params, Cardinal *num_params)
{
    XmTextFieldWidget tfw = (XmTextFieldWidget)w;

    DBGW("delete_next_word");

    if (!TextF_Editable(tfw))
    {
	return;
    }

    TextF_HighlightStart(tfw) = TextF_CursorPos(tfw);

    TextF_HighlightEnd(tfw) = SkipForward(tfw, WordEnd(tfw,
						       TextF_CursorPos(tfw)));

    TextDeleteHighlighted(tfw);

    MassiveChangeDraw(tfw);
}

static void
delete_previous_word(Widget w, XEvent *ev,
		     String *params, Cardinal *num_params)
{
    XmTextFieldWidget tfw = (XmTextFieldWidget)w;

    DBGW("delete_previous_word");

    if (!TextF_Editable(tfw))
    {
	return;
    }

    TextF_HighlightStart(tfw) = WordStart(tfw, SkipBackward(tfw,
							TextF_CursorPos(tfw)));

    TextF_HighlightEnd(tfw) = TextF_CursorPos(tfw);

    TextDeleteHighlighted(tfw);

    MassiveChangeDraw(tfw);
}

static void
delete_selection(Widget w, XEvent *ev,
		 String *params, Cardinal *num_params)
{
    XmTextFieldWidget tfw = (XmTextFieldWidget)w;

    DBGW("delete_selection");

    if (!TextF_Editable(tfw))
    {
	return;
    }

    TextDeleteHighlighted(tfw);

    MassiveChangeDraw(tfw);
}

static void
delete_to_end_of_line(Widget w, XEvent *ev,
		      String *params, Cardinal *num_params)
{
    XmTextFieldWidget tfw = (XmTextFieldWidget)w;

    DBGW("delete_to_end_of_line");

    if (!TextF_Editable(tfw))
    {
	return;
    }

    TextF_HighlightStart(tfw) = TextF_CursorPos(tfw);

    TextF_HighlightEnd(tfw) = TextF_Length(tfw);

    TextDeleteHighlighted(tfw);

    MassiveChangeDraw(tfw);
}

static void
delete_to_start_of_line(Widget w, XEvent *ev,
			String *params, Cardinal *num_params)
{
    XmTextFieldWidget tfw = (XmTextFieldWidget)w;

    DBGW("delete_to_start_of_line");

    if (!TextF_Editable(tfw))
    {
	return;
    }

    TextF_HighlightStart(tfw) = 0;

    TextF_HighlightEnd(tfw) = TextF_CursorPos(tfw);

    TextDeleteHighlighted(tfw);

    MassiveChangeDraw(tfw);
}

static void
delete_all(Widget w, XEvent *ev,
	   String *params, Cardinal *num_params)
{
    XmTextFieldWidget tfw = (XmTextFieldWidget)w;
    DBGW("delete_all");

    if (!TextF_Editable(tfw))
    {
	return;
    }

    TextF_HighlightStart(tfw) = 0;

    TextF_HighlightEnd(tfw) = TextF_Length(w);

    TextDeleteHighlighted(tfw);

    MassiveChangeDraw(tfw);
}

static void
deselect_all(Widget w, XEvent *ev,
	     String *params, Cardinal *num_params)
{
    DBGW("deselect_all");
}

static void
do_quick_action(Widget w, XEvent *ev,
		String *params, Cardinal *num_params)
{
    DBGW("do_quick_action");
}

static void
end_of_line(Widget w, XEvent *ev,
	    String *params, Cardinal *num_params)
{
    XmTextFieldWidget tfw = (XmTextFieldWidget)w;

    DBGW("end_of_line");

    if (!TextF_Editable(tfw))
    {
	return;
    }

    if (TextF_CursorPos(tfw) < TextF_Length(tfw))
    {
	XmTextPosition pos;

	pos = TextF_Length(tfw);

	DoCursorMove(tfw, ev, pos, True, True);
    }
}

static void
enter(Widget w, XEvent *ev,
      String *params, Cardinal *num_params)
{
    XmTextFieldWidget tfw = (XmTextFieldWidget)w;

    DBGW("enter");

    /* do some textfield specific stuff */

    XtCallActionProc(w, "PrimitiveEnter", ev, params, *num_params);

    if (TextF_Editable(tfw))
    {
	XmImSetFocusValues(w, NULL, 0);
    }
}

/*
 * extend-adjust : selects text from the anchor to the pointer position and
 *      deselects text outside that range.
 */
static void
extend_adjust(Widget w, XEvent *ev,
	      String *params, Cardinal *num_params)
{
    XmTextFieldWidget tfw = (XmTextFieldWidget)w;

    DBGW("extend_adjust");

    if (!TextF_AllowSelection(tfw))
    {
	return;
    }

    tfw->text.select_pos_x = ev->xbutton.x;

    if (ev->xbutton.x < TextF_XDraw(tfw) ||
	ev->xbutton.x > TextF_XDraw(tfw) + TextF_ViewWidth(tfw))
    {
	if (TextF_SelectId(tfw))
	{
	    ExtendHighlight(tfw);
	}
	else
	{
	    ExtendTimer((XtPointer)tfw, (XtIntervalId)0);
	}
    }
    else
    {
	if (TextF_SelectId(tfw))
	{
	    XtRemoveTimeOut(TextF_SelectId(tfw));
	    TextF_SelectId(tfw) = (XtIntervalId)0;
	}

	ExtendHighlight(tfw);
    }
}

/*
 * extend-end() : moves the insertion cursor to the position of the pointer
 */
static void
extend_end(Widget w, XEvent *ev,
	   String *params, Cardinal *num_params)
{
    XmTextFieldWidget tfw = (XmTextFieldWidget)w;

    DBGW("extend_end");

    if (!TextF_AllowSelection(tfw))
    {
	return;
    }

    if (TextF_SelectId(tfw))
    {
	XtRemoveTimeOut(TextF_SelectId(tfw));

	TextF_SelectId(tfw) = (XtIntervalId)0;
    }

    PrimarySelectionComplete(tfw, ev->xbutton.time);
}

/*
 * extend-start() : adjusts the anchor using te balance-beam method. Selects
 * text from the anchor to the pointer position and deselects text outside
 * that range.
 */
static void
extend_start(Widget w, XEvent *ev,
	     String *params, Cardinal *num_params)
{
    XmTextFieldWidget tfw = (XmTextFieldWidget)w;
    int pos;

    DBGW("extend_start");

    XmProcessTraversal(w, XmTRAVERSE_CURRENT);

    if (!TextF_AllowSelection(tfw))
    {
	return;
    }

    pos = TextPixelToSelectionPos(tfw, ev->xbutton.x);
    DoCursorMove(tfw, ev, pos, False, True);

    if (TextF_HighlightStart(tfw) < 0)
    {
	TextF_HighlightStart(tfw) =
	    TextF_HighlightEnd(tfw) =
	    TextF_HighlightPivot(tfw) = TextF_CursorPos(tfw);
    }

    if (TextF_CursorPos(tfw) < TextF_HighlightPivot(tfw))
    {
	TextF_HighlightStart(tfw) = TextF_CursorPos(tfw);
    }
    else
    {
	TextF_HighlightEnd(tfw) = TextF_CursorPos(tfw);
    }
}

static void
forward_character(Widget w, XEvent *ev,
		  String *params, Cardinal *num_params)
{
    XmTextFieldWidget tfw = (XmTextFieldWidget)w;

    DBGW("forward_character");

    if (!TextF_Editable(tfw))
    {
	return;
    }

    if (TextF_CursorPos(tfw) < TextF_Length(tfw))
    {
	XmTextPosition pos;

	pos = TextF_CursorPos(tfw) + 1;

	DoCursorMove(tfw, ev, pos, True, True);
    }
}

static void
forward_word(Widget w, XEvent *ev,
	     String *params, Cardinal *num_params)
{
    XmTextFieldWidget tfw = (XmTextFieldWidget)w;
    DBGW("forward_word");

    if (!TextF_Editable(tfw))
    {
	return;
    }

    if (TextF_CursorPos(tfw) < TextF_Length(tfw))
    {
	XmTextPosition pos;

	pos = SkipForward(tfw, WordEnd(tfw, TextF_CursorPos(tfw)));

	DoCursorMove(tfw, ev, pos, True, True);
    }
}

static void
grab_focus(Widget w, XEvent *ev,
	   String *params, Cardinal *num_params)
{
    XmTextFieldWidget tfw = (XmTextFieldWidget)w;
    XmTextPosition pos;

    DBGW("grab_focus");

    XmProcessTraversal((Widget)tfw, XmTRAVERSE_CURRENT);

    if (!TextF_AllowSelection(tfw))
    {
	return;
    }

    pos = TextPixelToSelectionPos(tfw, ev->xbutton.x);

    if ((tfw->text.last_time + XtGetMultiClickTime(XtDisplay((Widget)tfw))) >
	ev->xbutton.time)
    {
	tfw->text.sarray_index++;
    }
    else
    {
	tfw->text.sarray_index = 0;
    }

    DoScanType(tfw, ev, pos);

    tfw->text.last_time = ev->xbutton.time;
}

static void
Help(Widget w, XEvent *ev,
     String *params, Cardinal *num_params)
{
    DBGW("help");
}

static void
insert_string(Widget w, XEvent *ev,
	      String *params, Cardinal *num_params)
{
    DBGW("insert_string");
}

static void
key_select(Widget w, XEvent *ev,
	   String *params, Cardinal *num_params)
{
    DBGW("key_select");
}

static void
kill_next_character(Widget w, XEvent *ev,
		    String *params, Cardinal *num_params)
{
    XmTextFieldWidget tfw = (XmTextFieldWidget)w;

    DBGW("kill_next_character");

    delete_next_character((Widget)tfw, ev, params, num_params);
}

static void
kill_next_word(Widget w, XEvent *ev,
	       String *params, Cardinal *num_params)
{
    XmTextFieldWidget tfw = (XmTextFieldWidget)w;

    DBGW("kill_next_word");

    delete_next_word((Widget)tfw, ev, params, num_params);
}

static void
kill_previous_character(Widget w, XEvent *ev,
			String *params, Cardinal *num_params)
{
    XmTextFieldWidget tfw = (XmTextFieldWidget)w;

    DBGW("kill_previous_character");

    delete_previous_character((Widget)tfw, ev, params, num_params);
}

static void
kill_previous_word(Widget w, XEvent *ev,
		   String *params, Cardinal *num_params)
{
    XmTextFieldWidget tfw = (XmTextFieldWidget)w;

    DBGW("kill_previous_word");

    delete_previous_word((Widget)tfw, ev, params, num_params);
}

static void
kill_selection(Widget w, XEvent *ev,
	       String *params, Cardinal *num_params)
{
    DBGW("kill_selection");
}

static void
kill_to_end_of_line(Widget w, XEvent *ev,
		    String *params, Cardinal *num_params)
{
    DBGW("kill_to_end_of_line");
}

static void
kill_to_start_of_line(Widget w, XEvent *ev,
		      String *params, Cardinal *num_params)
{
    DBGW("kill_to_start_of_line");
}

static void
leave(Widget w, XEvent *ev,
      String *params, Cardinal *num_params)
{
    XmTextFieldWidget tfw = (XmTextFieldWidget)w;

    DBGW("leave");

    /* do some textfield specific stuff */

    XtCallActionProc((Widget)tfw, "PrimitiveLeave", ev, params, *num_params);

    if (TextF_Editable(tfw))
    {
	XmImUnsetFocus((Widget)tfw);
    }
}

static void
move_destination(Widget w, XEvent *ev,
		 String *params, Cardinal *num_params)
{
    DBGW("move_destination");
}

static void
move_to(Widget w, XEvent *ev,
	String *params, Cardinal *num_params)
{
    DBGW("move_to");
}

static void
next_tab_group(Widget w, XEvent *ev,
	       String *params, Cardinal *num_params)
{
    DBGW("next_tab_group");

    XtCallActionProc(w, "PrimitiveNextTabGroup", ev, params, *num_params);
}

static void
page_left(Widget w, XEvent *ev,
	  String *params, Cardinal *num_params)
{
    XmTextFieldWidget tfw = (XmTextFieldWidget)w;

    DBGW("page_left");

    if (!TextF_Editable(tfw))
    {
	return;
    }

    if (TextF_CursorPos(tfw) > 0)
    {
	XmTextPosition pos;

	pos = TextPixelToPos(tfw, TextF_XDraw(tfw) - TextF_ViewWidth(tfw));

	DoCursorMove(tfw, ev, pos, True, True);
    }
}

static void
page_right(Widget w, XEvent *ev,
	   String *params, Cardinal *num_params)
{
    XmTextFieldWidget tfw = (XmTextFieldWidget)w;

    DBGW("page_right");

    if (!TextF_Editable(tfw))
    {
	return;
    }

    if (TextF_CursorPos(tfw) < TextF_Length(tfw))
    {
	XmTextPosition pos;

	pos = TextPixelToPos(tfw, TextF_XDraw(tfw) + TextF_ViewWidth(tfw));

	DoCursorMove(tfw, ev, pos, True, True);
    }
}

static void
paste_clipboard(Widget w, XEvent *ev,
		String *params, Cardinal *num_params)
{
    DBGW("paste_clipboard");
}

static void
paste_primary(Widget w, XEvent *ev,
	      String *params, Cardinal *num_params)
{
    DBGW("paste_primary");
}

static void
prev_tab_group(Widget w, XEvent *ev,
	       String *params, Cardinal *num_params)
{
    DBGW("prev_tab_group");

    XtCallActionProc(w, "PrimitivePrevTabGroup", ev, params, *num_params);
}

static void
process_bdrag(Widget w, XEvent *ev,
	      String *params, Cardinal *num_params)
{
    DBGW("process_bdrag");
}

static void
process_cancel(Widget w, XEvent *ev,
	       String *params, Cardinal *num_params)
{
    DBGW("process_cancel");
}

static void
process_home(Widget w, XEvent *ev,
	     String *params, Cardinal *num_params)
{
    DBGW("process_home");
}

static void
process_return(Widget w, XEvent *ev,
	       String *params, Cardinal *num_params)
{
    DBGW("process_return");
}

static void
process_tab(Widget w, XEvent *ev,
	    String *params, Cardinal *num_params)
{
    DBGW("process_tab");
}

static void
quick_copy_set(Widget w, XEvent *ev,
	       String *params, Cardinal *num_params)
{
    DBGW("quick_copy_set");
}

static void
quick_cut_set(Widget w, XEvent *ev,
	      String *params, Cardinal *num_params)
{
    DBGW("quick_cut_set");
}

static void
redraw_display(Widget w, XEvent *ev,
	       String *params, Cardinal *num_params)
{
    DBGW("redraw_display");
    Draw((XmTextFieldWidget)w);
}

static void
secondary_adjust(Widget w, XEvent *ev,
		 String *params, Cardinal *num_params)
{
    DBGW("secondary_adjust");
}

static void
secondary_notify(Widget w, XEvent *ev,
		 String *params, Cardinal *num_params)
{
    DBGW("secondary_notify");
}

static void
secondary_start(Widget w, XEvent *ev,
		String *params, Cardinal *num_params)
{
    DBGW("secondary_start");
}

static void
select_adjust(Widget w, XEvent *ev,
	      String *params, Cardinal *num_params)
{
    DBGW("select_adjust");
}

static void
select_all(Widget w, XEvent *ev,
	   String *params, Cardinal *num_params)
{
    XmTextFieldWidget tfw = (XmTextFieldWidget)w;

    DBGW("select_all");

    TextF_HighlightPivot(tfw) = TextF_HighlightStart(tfw) = 0;
    TextF_HighlightEnd(tfw) = TextF_Length(tfw);

    /* FIX ME - what event type should this be? */
    PrimarySelectionComplete(tfw, ev->xbutton.time);

    Draw(tfw);
}

static void
select_end(Widget w, XEvent *ev,
	   String *params, Cardinal *num_params)
{
    DBGW("select_end");
}

static void
select_start(Widget w, XEvent *ev,
	     String *params, Cardinal *num_params)
{
    XmTextFieldWidget tfw = (XmTextFieldWidget)w;

    DBGW("select_start");

    grab_focus((Widget)tfw, ev, params, num_params);
}

static void
self_insert(Widget w, XEvent *ev,
	    String *params, Cardinal *num_params)
{
#define INSERTCHARBUFSIZ 32
    XmTextFieldWidget tfw = (XmTextFieldWidget)w;
    char buf[INSERTCHARBUFSIZ];
    KeySym keysym;
    int len, status;

    DBGW("self_insert");

    if (!TextF_Editable(tfw))
    {
	if (TextF_VerifyBell(tfw))
	{
	    beep((Widget)tfw, ev, params, num_params);
	}
	return;
    }

    len = XmImMbLookupString((Widget)tfw,
			     (XKeyPressedEvent *)ev, buf,
			     INSERTCHARBUFSIZ,
			     &keysym,
			     &status);

    if (XdbInDebug(__FILE__, (Widget)tfw))
    {
	DEBUGOUT(XdbDebug(__FILE__, (Widget)tfw,
			  "XmImMbLookupString => %d\n", len));

	DEBUGOUT(XdbDebug0(__FILE__, (Widget)tfw, "\tStatus %s\n",
			   (status == XLookupNone) ? "none" :
			   (status == XLookupChars) ? "chars" :
			   (status == XLookupBoth) ? "both" :
			   (status == XLookupKeySym) ? "keysym" :
			   (status == XBufferOverflow) ? "overflow" : "????"));

	if (status == XLookupBoth || status == XLookupKeySym)
	{
	    DEBUGOUT(XdbDebug0(__FILE__, (Widget)tfw,
			       "\tKeySym 0x%X\n", keysym));
	}
	if (len > 0)
	{
	    int i;

	    DEBUGOUT(XdbDebug0(__FILE__, (Widget)tfw, "\tBuffer "));
	    for (i = 0; i < len; i++)
	    {
		DEBUGOUT(XdbDebug(__FILE__, (Widget)tfw, " %X", 0xFF & buf[i]));
	    }

	    DEBUGOUT(XdbDebug0(__FILE__, (Widget)tfw, "\n"));
	}
    }

    if (len > 0)
    {				/* FIX ME */
	if (status == XLookupBoth || status == XLookupChars)
	{
	    DoInsert(tfw, ev, buf, len);
	}
    }
}

static void
set_anchor(Widget w, XEvent *ev,
	   String *params, Cardinal *num_params)
{
    DBGW("set_anchor");
}

static void
set_insertion_point(Widget w, XEvent *ev,
		    String *params, Cardinal *num_params)
{
    DBGW("set_insertion_point");
}

static void
set_selection_hint(Widget w, XEvent *ev,
		   String *params, Cardinal *num_params)
{
    DBGW("set_selection_hint");
}

static void
toggle_add_mode(Widget w, XEvent *ev,
		String *params, Cardinal *num_params)
{
    DBGW("toggle_add_mode");
}

static void
traverse_home(Widget w, XEvent *ev,
	      String *params, Cardinal *num_params)
{
    XmTextFieldWidget tfw = (XmTextFieldWidget)w;

    DBGW("traverse_home");

    XmProcessTraversal((Widget)tfw, XmTRAVERSE_HOME);
}

static void
traverse_next(Widget w, XEvent *ev,
	      String *params, Cardinal *num_params)
{
    XmTextFieldWidget tfw = (XmTextFieldWidget)w;

    DBGW("traverse_next");

    XmProcessTraversal((Widget)tfw, XmTRAVERSE_NEXT);
}

static void
traverse_prev(Widget w, XEvent *ev,
	      String *params, Cardinal *num_params)
{
    XmTextFieldWidget tfw = (XmTextFieldWidget)w;

    DBGW("traverse_prev");

    XmProcessTraversal((Widget)tfw, XmTRAVERSE_PREV);
}

static void
unkill(Widget w, XEvent *ev,
       String *params, Cardinal *num_params)
{
    DBGW("unkill");
}

static void
unmap(Widget w, XEvent *ev,
      String *params, Cardinal *num_params)
{
    DBGW("unmap");
}


/*
 * Public functions -----------------------------------------------------------
 */

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

void
XmTextFieldClearSelection(Widget aw, Time time)
{
    XmTextFieldWidget w = (XmTextFieldWidget)aw;

    if (!XmIsTextField(w))
    {
	return;
    }
    /* FIX ME */

}

Boolean
XmTextFieldCopy(Widget aw, Time time)
{
    XmTextFieldWidget w = (XmTextFieldWidget)aw;

    if (!XmIsTextField(w))
    {
	return False;
    }
    /* FIX ME */

    return False;
}

Boolean
XmTextFieldCut(Widget aw, Time time)
{
    XmTextFieldWidget w = (XmTextFieldWidget)aw;

    if (!XmIsTextField(w))
    {
	return False;
    }
    /* FIX ME */

    return False;
}

int
XmTextFieldGetBaseline(Widget aw)
{
    XmTextFieldWidget w = (XmTextFieldWidget)aw;

    if (!XmIsTextField(w))
    {
	return 0;
    }

    return TextF_YOffset(w);
}

XmTextPosition
XmTextFieldGetCursorPosition(Widget aw)
{
    XmTextFieldWidget w = (XmTextFieldWidget)aw;

    if (!XmIsTextField(w))
    {
	return 0;
    }

    return TextF_CursorPos(w);
}

Boolean
XmTextFieldGetEditable(Widget aw)
{
    XmTextFieldWidget w = (XmTextFieldWidget)aw;

    if (!XmIsTextField(w))
    {
	return 0;
    }

    return TextF_Editable(w);
}

XmTextPosition
XmTextFieldGetInsertionPosition(Widget aw)
{
    XmTextFieldWidget w = (XmTextFieldWidget)aw;

    if (!XmIsTextField(w))
    {
	return 0;
    }

    return TextF_CursorPos(w);
}

XmTextPosition
XmTextFieldGetLastPosition(Widget aw)
{
    XmTextFieldWidget w = (XmTextFieldWidget)aw;

    if (!XmIsTextField(w))
    {
	return 0;
    }

    return TextF_Length(w);
}

int
XmTextFieldGetMaxLength(Widget aw)
{
    XmTextFieldWidget w = (XmTextFieldWidget)aw;

    if (!XmIsTextField(w))
    {
	return 0;
    }

    return TextF_MaxLength(w);
}

char *
XmTextFieldGetSelection(Widget aw)
{
    XmTextFieldWidget w = (XmTextFieldWidget)aw;

    if (!XmIsTextField(w))
    {
	return NULL;
    }
    /* FIX ME */

    return NULL;
}

Boolean
XmTextFieldGetSelectionPosition(Widget aw,
				XmTextPosition *left, XmTextPosition *right)
{
    XmTextFieldWidget w = (XmTextFieldWidget)aw;

    if (!XmIsTextField(w))
    {
	return False;
    }
    /* FIX ME */

    return False;
}

wchar_t *
XmTextFieldGetSelectionWcs(Widget aw)
{
    XmTextFieldWidget w = (XmTextFieldWidget)aw;

    if (!XmIsTextField(w))
    {
	return NULL;
    }
    /* FIX ME */

    return NULL;
}

char *
XmTextFieldGetString(Widget aw)
{
    XmTextFieldWidget w = (XmTextFieldWidget)aw;
    char *ret;

    if (!XmIsTextField(w))
    {
	ret = XtMalloc(1);
	*ret = '\0';
	return ret;
    }

    ret = XtMalloc(TextF_Length(w) + 1);
    strncpy(ret, TextF_Value(w), TextF_Length(w));
    ret[TextF_Length(w)] = '\0';
    return ret;
}

wchar_t *
XmTextFieldGetStringWcs(Widget aw)
{
    XmTextFieldWidget w = (XmTextFieldWidget)aw;

    if (!XmIsTextField(w))
    {
	return NULL;
    }
    /* FIX ME */

    return NULL;
}

int
XmTextFieldGetSubstring(Widget aw, XmTextPosition start, int num_chars,
			int buffer_size, char *buffer)
{
    int len;
    int retval = XmCOPY_SUCCEEDED;
    XmTextFieldWidget w = (XmTextFieldWidget)aw;

    if (!XmIsTextField(aw))
    {
	return XmCOPY_FAILED;
    }

    if (start < 0 || start > TextF_Length(w))
    {
	return XmCOPY_FAILED;
    }

    /* FIX ME */
    if (num_chars > buffer_size)
    {
	len = num_chars;
    }
    else
    {
	len = buffer_size - 1;
	retval = XmCOPY_TRUNCATED;
    }

    if (start + len > TextF_Length(w))
    {
	len = TextF_Length(w) - start;
    }

    strncpy(buffer, TextF_Value(w) + start, len);
    buffer[len] = '\0';

    return retval;
}

int
XmTextFieldGetSubstringWcs(Widget aw, XmTextPosition start,
			   int num_chars, int buffer_size,
			   wchar_t *buffer)
{
    XmTextFieldWidget w = (XmTextFieldWidget)aw;

    if (!XmIsTextField(w))
    {
	return XmCOPY_FAILED;
    }
    /* FIX ME */

    return 0;
}

void
XmTextFieldInsert(Widget aw, XmTextPosition pos, char *str)
{
    XmTextFieldWidget w = (XmTextFieldWidget)aw;
    XmTextPosition len;

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

    if (str && ((len = strlen(str)) > 0) && pos >= 0 && pos <= TextF_Length(w))
    {
	TextF_HighlightStart(w) = TextF_HighlightEnd(w) = pos;
	TextInsert(w, str, len);
	MassiveChangeDraw(w);
    }
}

void
XmTextFieldInsertWcs(Widget aw, XmTextPosition position, wchar_t *wcstring)
{
    XmTextFieldWidget w = (XmTextFieldWidget)aw;

    if (!XmIsTextField(w))
    {
	return;
    }
    /* FIX ME */
}

Boolean
XmTextFieldPaste(Widget aw)
{
    XmTextFieldWidget w = (XmTextFieldWidget)aw;

    if (!XmIsTextField(w))
    {
	return False;
    }
    /* FIX ME */

    return False;
}

Boolean
XmTextFieldPosToXY(Widget aw, XmTextPosition position, Position *x, Position *y)
{
    XmTextFieldWidget w = (XmTextFieldWidget)aw;
    int pixel;

    if (!XmIsTextField(w))
    {
	return False;
    }

    if (position < 0 || position > TextF_Length(w))
    {
	return False;
    }

    pixel = TextF_XOffset(w) + TextF_FontTextWidth(w, TextF_Value(w), position);
    if (pixel < TextF_XDraw(w) || pixel > (TextF_XDraw(w) + TextF_ViewWidth(w)))
    {
	return False;
    }

    *x = (Position)pixel;
    *y = (Position)TextF_YOffset(w);

    return True;
}

Boolean
XmTextFieldRemove(Widget aw)
{
    XmTextFieldWidget w = (XmTextFieldWidget)aw;

    if (!XmIsTextField(w))
    {
	return False;
    }
    /* FIX ME */

    return False;
}

void
XmTextFieldReplace(Widget aw, XmTextPosition first,
		   XmTextPosition last, char *str)
{
    XmTextFieldWidget w = (XmTextFieldWidget)aw;
    XmTextPosition len;

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

    if (str)
    {
	len = strlen(str);
	if (last > TextF_Length(w))
	    last = TextF_Length(w);
	if (first <= last)
	{
	    TextF_HighlightStart(w) = first;
	    TextF_HighlightEnd(w) = last;

	    TextDeleteHighlighted(w);

	    TextInsert(w, str, len);

	    MassiveChangeDraw(w);
	}
    }
}

void
XmTextFieldReplaceWcs(Widget aw, XmTextPosition from_pos,
		      XmTextPosition to_pos, wchar_t *wcstring)
{
    XmTextFieldWidget w = (XmTextFieldWidget)aw;

    if (!XmIsTextField(w))
    {
	return;
    }
    /* FIX ME */
}

void
XmTextFieldSetAddMode(Widget aw, Boolean state)
{
    XmTextFieldWidget w = (XmTextFieldWidget)aw;

    if (!XmIsTextField(w))
    {
	return;
    }
    /* FIX ME */
}

void
XmTextFieldSetCursorPosition(Widget aw, XmTextPosition pos)
{
    XmTextFieldWidget w = (XmTextFieldWidget)aw;

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

    if (pos >= 0 && pos <= TextF_Length(w))
    {
	TextF_CursorPos(w) = pos;

	MassiveChangeDraw(w);
    }
}

static void
_XmTextFieldSetEditable(Widget w, Boolean e)
{
    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);
    }
}

void
XmTextFieldSetEditable(Widget aw, Boolean editable)
{
    XmTextFieldWidget w = (XmTextFieldWidget)aw;

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

    if (TextF_Editable(w) != editable)
    {
	_XmTextFieldSetEditable(aw, editable);
    }

    TextF_Editable(w) = editable;
}

void
XmTextFieldSetHighlight(Widget aw, XmTextPosition left, XmTextPosition right, XmHighlightMode mode)
{
    XmTextFieldWidget w = (XmTextFieldWidget)aw;

    if (!XmIsTextField(w))
    {
	return;
    }
    /* FIX ME */
}

void
XmTextFieldSetInsertionPosition(Widget aw, XmTextPosition pos)
{
    XmTextFieldWidget w = (XmTextFieldWidget)aw;

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

    if (pos >= 0 && pos <= TextF_Length(w))
    {
	TextF_CursorPos(w) = pos;

	MassiveChangeDraw(w);
    }
}

void
XmTextFieldSetMaxLength(Widget aw, int max_length)
{
    XmTextFieldWidget w = (XmTextFieldWidget)aw;

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

    TextF_MaxLength(w) = max_length;

    if (TextF_Length(w) > max_length)
    {
	TextF_Length(w) = max_length;
	TextF_Value(w)[max_length] = '\0';

	if (TextF_CursorPos(w) > max_length)
	{
	    TextF_CursorPos(w) = max_length;
	}

	MassiveChangeDraw(w);
    }
}

/* ARGSUSED */
void
XmTextFieldSetSelection(Widget aw, XmTextPosition start,
			XmTextPosition end, Time time)
{
    XmTextFieldWidget w = (XmTextFieldWidget)aw;

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

    if (end < start)
    {
	XmTextPosition temp;

	temp = start;
	start = end;
	end = temp;
    }
    if (start < 0)
    {
	start = 0;
    }
    if (end > TextF_Length(w))
    {
	end = TextF_Length(w);
    }

    TextF_HighlightStart(w) = start;
    TextF_HighlightEnd(w) = TextF_CursorPos(w) = end;

    MassiveChangeDraw(w);
}

void
XmTextFieldSetString(Widget aw, char *str)
{
    XmTextFieldWidget w = (XmTextFieldWidget)aw;
    XmTextPosition len = 0;
    XmTextVerifyCallbackStruct cbs;
    XmTextBlockRec tb;


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

    if (str)
    {
	len = strlen(str);
    }
    cbs.event = NULL;
    cbs.doit = True;
    cbs.currInsert = TextF_CursorPos(w);
    cbs.newInsert = 0;
    cbs.startPos = 0;
    cbs.endPos = TextF_Length(w);
    tb.ptr = str;
    tb.length = len;
    tb.format = XmFMT_8_BIT;
    cbs.text = &tb;
    if (TextF_ModifyVerifyCallback(w))
    {
	cbs.reason = XmCR_MODIFYING_TEXT_VALUE;
	XtCallCallbacks(aw, XmNmodifyVerifyCallback, &cbs);
    }
    if (TextF_WcsModifyVerifyCallback(w))
    {
	/* FIX ME */
	XtCallCallbacks(aw, XmNmodifyVerifyCallbackWcs, &cbs);
    }
    if (cbs.text->ptr && cbs.doit)
    {
	len = strlen(cbs.text->ptr);

	TextF_HighlightStart(w) = cbs.startPos;
	TextF_HighlightEnd(w) = cbs.endPos;

	TextDeleteHighlighted(w);

	TextInsert(w, cbs.text->ptr, len);

	TextF_CursorPos(w) = cbs.startPos;

	MassiveChangeDraw(w);

	if (TextF_ValueChangedCallback(w))
	{
	    cbs.reason = XmCR_VALUE_CHANGED;
	    XtCallCallbacks(aw, XmNvalueChangedCallback, &cbs);
	}
	if (TextF_MotionVerifyCallback(w))
	{
	    XtCallCallbacks(aw, XmNmotionVerifyCallback, &cbs);
	}
    }
}

void
XmTextFieldSetStringWcs(Widget w, wchar_t *wc_value)
{
    /* FIX ME */
}

void
XmTextFieldShowPosition(Widget aw, XmTextPosition position)
{
    XmTextFieldWidget w = (XmTextFieldWidget)aw;

    if (!XmIsTextField(w))
    {
	return;
    }
    /* FIX ME */
}

XmTextPosition
XmTextFieldXYToPos(Widget aw, Position x, Position y)
{
    XmTextFieldWidget w = (XmTextFieldWidget)aw;

    if (!XmIsTextField(w))
    {
	return 0;
    }

    return TextPixelToSelectionPos(w, x);
}

static XtPointer
_XmTextF_TraitGetValue(Widget w, int format)
{
	switch (format) {
	case XmFORMAT_XmSTRING:
		return XmStringCreateSimple(TextF_Value(w));
	case XmFORMAT_MBYTE:
		return XmTextFieldGetString(w);	/* FIX ME */
	case XmFORMAT_WCS:
		return XmTextFieldGetString(w);	/* FIX ME */
	default:
		return NULL;
	}
}

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

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

static int
_XmTextF_TraitPreferredFormat(Widget w)
{
	return XmFORMAT_WCS;
}
