/* 
 *  @OPENGROUP_COPYRIGHT@
 *  COPYRIGHT NOTICE
 *  Copyright (c) 1990, 1991, 1992, 1993 Open Software Foundation, Inc.
 *  Copyright (c) 1996, 1997, 1998, 1999, 2000 The Open Group
 *  ALL RIGHTS RESERVED (MOTIF). See the file named COPYRIGHT.MOTIF for
 *  the full copyright text.
 *  
 *  This software is subject to an open license. It may only be
 *  used on, with or for operating systems which are themselves open
 *  source systems. You must contact The Open Group for a license
 *  allowing distribution and sublicensing of this software on, with,
 *  or for operating systems which are not Open Source programs.
 *  
 *  See http://www.opengroup.org/openmotif/license for full
 *  details of the license agreement. Any use, reproduction, or
 *  distribution of the program constitutes recipient's acceptance of
 *  this agreement.
 *  
 *  EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS
 *  PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 *  KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY
 *  WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY
 *  OR FITNESS FOR A PARTICULAR PURPOSE
 *  
 *  EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT
 *  NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT,
 *  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 *  DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED
 *  AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *  ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE
 *  EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGES.
*/ 
/* 
 * HISTORY
*/ 
#ifdef REV_INFO
#ifndef lint
static char rcsid[] = "$TOG: TextF.c /main/65 1999/09/01 17:28:48 mgreess $"
#endif
#endif
/* (c) Copyright 1989, 1990, 1991, 1992 HEWLETT-PACKARD COMPANY */

#include <stdio.h>
#include <limits.h>		/* required for MB_LEN_MAX definition */
#include <string.h>
#include <ctype.h>
#include "XmI.h"
#include <X11/ShellP.h>
#include <X11/VendorP.h>
#include <X11/Xatom.h>
#include <X11/keysym.h>
#include <Xm/AccColorT.h>
#include <Xm/AccTextT.h>
#include <Xm/AtomMgr.h>
#include <Xm/CutPaste.h>
#include <Xm/Display.h>
#include <Xm/DragC.h>
#include <Xm/DragIcon.h>
#include <Xm/DragIconP.h>
#include <Xm/DrawP.h>
#include <Xm/DropSMgr.h>
#include <Xm/DropTrans.h>
#include <Xm/ManagerP.h>
#include <Xm/TraitP.h>
#include <Xm/TransferP.h>
#include <Xm/TransltnsP.h>
#include <Xm/XmosP.h>
#include "DestI.h"
#include "DisplayI.h"
#include "GMUtilsI.h"
#include "ImageCachI.h"
#include "MessagesI.h"
#include "RepTypeI.h"
#include "ScreenI.h"
#include "TextFI.h"
#include "TextFSelI.h"
#include "TravActI.h"
#include "TraversalI.h"
#include "VendorSEI.h"
#include "XmStringI.h"
#include <Xm/PrintSP.h>         /* for XmIsPrintShell */


#if defined(__FreeBSD__)
/*
 * Modification by Integrated Computer Solutions, Inc.  May 2000
 *
 * FreeBSD does not include the necessary wide character string
 * functions.  Use the internal _Xwc... routines and add the
 * other missing functions as _Xmwc... routines.  The new functions
 * are added static to this file.
 */
#define wcslen(c) _Xwcslen(c)
#define wcscpy(d,s) _Xwcscpy(d,s)
#define wcsncpy(d,s,l) _Xwcsncpy(d,s,l)

static wchar_t* _Xmwcschr(const wchar_t *ws, wchar_t wc)
{
        for (;; ++ws) {
                if (*ws == wc)
                        return((wchar_t *)ws);
                if (!*ws)
                        return((wchar_t *)NULL);
        }
        /* NOTREACHED */
}
#define wcschr(w,c) _Xmwcschr(w,c)

static wchar_t* _Xmwcscat(wchar_t *ws1, const wchar_t *ws2)
{
        wchar_t *save = ws1;

        for (; *ws1; ++ws1);
        while (*ws1++ = *ws2++);
        return save;
}
#define wcscat(w1,w2) _Xmwcscat(w1,w2)

static wchar_t* _Xmwcsncat(wchar_t *ws1, const wchar_t *ws2, size_t n)
{
        if (n != 0) {
                register wchar_t *d = ws1;
                register const wchar_t *s = ws2;

                while (*d != 0)
                        d++;
                do {
                        if ((*d = *s++) == 0)
                                break;
                        d++;
                } while (--n != 0);
                *d = 0;
        }
        return ws1;
}
#define wcsncat(w1,w2,l) _Xmwcsncat(w1,w2,l)

#else  /* !__FreeBSD__ */
#include <wchar.h>
#endif /* __FreeBSD__ */

#define MSG1		_XmMMsgTextF_0000
#define MSG2		_XmMMsgTextF_0001
#define MSG3		_XmMMsgTextF_0002
#define MSG4		_XmMMsgTextF_0003
#define MSG5		_XmMMsgTextF_0004
#define MSG7		_XmMMsgTextF_0006
#define WC_MSG1		_XmMMsgTextFWcs_0000
#define GRABKBDERROR	_XmMMsgRowColText_0024

#define TEXT_INCREMENT		 32
#define PRIM_SCROLL_INTERVAL	100
#define SEC_SCROLL_INTERVAL	200
#define XmDYNAMIC_BOOL		255

/* For the action parameters that are processed as reptypes */
#define _RIGHT 0
#define _LEFT  1

#define EventBindings1	_XmTextF_EventBindings1
#define EventBindings2	_XmTextF_EventBindings2
#define EventBindings3	_XmTextF_EventBindings3

#define TEXT_MAX_INSERT_SIZE 64    /* Size of buffer for XLookupString. */

typedef struct {
  Boolean has_destination;
  XmTextPosition position;
  int replace_length;
  Boolean quick_key;
} TextFDestDataRec, *TextFDestData;

/********    Static Function Declarations    ********/

static void MakeCopy(Widget w,
		     int n,
		     XtArgVal *value);

static void WcsMakeCopy(Widget w,
                        int n,
                        XtArgVal *value);

static void FreeContextData(Widget w,
			    XtPointer clientData,
			    XtPointer callData);

static TextFDestData GetTextFDestData(Widget w);

static _XmHighlightRec * FindHighlight(XmTextFieldWidget w,
				       XmTextPosition position);

static void InsertHighlight(XmTextFieldWidget w,
			    XmTextPosition position,
			    XmHighlightMode mode);

static void TextFieldSetHighlight(XmTextFieldWidget tf,
				  XmTextPosition left,
				  XmTextPosition right,
				  XmHighlightMode mode);

static Boolean GetXYFromPos(XmTextFieldWidget tf,
			    XmTextPosition position,
			    Position *x,
			    Position *y);

static Boolean CurrentCursorState(XmTextFieldWidget tf);

static void PaintCursor(XmTextFieldWidget tf);

static void BlinkInsertionPoint(XmTextFieldWidget tf);

static void HandleTimer(XtPointer closure,
                        XtIntervalId *id);

static void ChangeBlinkBehavior(XmTextFieldWidget tf,
#if NeedWidePrototypes
				int turn_on);

#else
                                Boolean turn_on);
#endif /* NeedWidePrototypes */
static void GetRect(XmTextFieldWidget tf,
                    XRectangle *rect);

static void SetFullGC(XmTextFieldWidget tf,
                        GC gc);

static void SetMarginGC(XmTextFieldWidget tf,
                          GC gc);

static void SetNormGC(XmTextFieldWidget tf,
                        GC gc,
#if NeedWidePrototypes
                        int change_stipple,
                        int stipple);
#else
                        Boolean change_stipple,
                        Boolean stipple);
#endif /* NeedWidePrototypes */

static void SetInvGC(XmTextFieldWidget tf,
		       GC gc);

static void DrawText(XmTextFieldWidget tf,
		     GC gc,
		     int x,
		     int y,
		     char *string,
		     int length);

static int FindPixelLength(XmTextFieldWidget tf,
			   char *string,
			   int length);

static void DrawTextSegment(XmTextFieldWidget tf,
			    XmHighlightMode mode,
			    XmTextPosition prev_seg_start,
			    XmTextPosition seg_start,
			    XmTextPosition seg_end,
			    XmTextPosition next_seg,
#if NeedWidePrototypes
			    int stipple,
#else
			    Boolean stipple,
#endif /* NeedWidePrototypes */
			    int y,
			    int *x);

static void RedisplayText(XmTextFieldWidget tf,
			  XmTextPosition start,
			  XmTextPosition end);

static void ComputeSize(XmTextFieldWidget tf,
                        Dimension *width,
                        Dimension *height);

static XtGeometryResult TryResize(XmTextFieldWidget tf,
#if NeedWidePrototypes
				  int width,
				  int height);
#else
                                  Dimension width,
                                  Dimension height);
#endif /* NeedWidePrototypes */

static Boolean AdjustText(XmTextFieldWidget tf,
			  XmTextPosition position,
#if NeedWidePrototypes
			  int flag);
#else
                          Boolean flag);
#endif /* NeedWidePrototypes */

static void AdjustSize(XmTextFieldWidget tf);

static Boolean ModifyVerify(XmTextFieldWidget tf,
			    XEvent *event,
			    XmTextPosition *replace_prev,
			    XmTextPosition *replace_next,
			    char **insert,
			    int *insert_length,
			    XmTextPosition *newInsert,
			    int *free_insert);

static void ResetClipOrigin(XmTextFieldWidget tf);

static void InvertImageGC(XmTextFieldWidget tf);

static void ResetImageGC(XmTextFieldWidget tf);

typedef enum { ForceTrue, DontCare } PassDisown;
static void SetCursorPosition(XmTextFieldWidget tf,
			      XEvent *event,
			      XmTextPosition position,
#if NeedWidePrototypes
			      int adjust_flag,
			      int call_cb,
			      int set_dest,
#else
                              Boolean adjust_flag,
                              Boolean call_cb,
                              Boolean set_dest,
#endif /* NeedWidePrototypes */
			      PassDisown passDisown);

static void VerifyBounds(XmTextFieldWidget tf,
			 XmTextPosition *from,
			 XmTextPosition *to);

static XmTextPosition GetPosFromX(XmTextFieldWidget tf,
#if NeedWidePrototypes
				  int x);
#else
                                  Position x);
#endif /* NeedWidePrototypes */

static Boolean SetDestination(Widget w,
			      XmTextPosition position,
#if NeedWidePrototypes
			      int disown,
#else
			      Boolean disown,
#endif /* NeedWidePrototypes */
			      Time set_time);

static Boolean VerifyLeave(XmTextFieldWidget tf,
			   XEvent *event);

static Boolean _XmTextFieldIsWordBoundary(XmTextFieldWidget tf,
					  XmTextPosition pos1,
					  XmTextPosition pos2);

static Boolean _XmTextFieldIsWSpace(wchar_t wide_char,
				    wchar_t *white_space,
				    int num_entries);

static void FindWord(XmTextFieldWidget tf,
		     XmTextPosition begin,
		     XmTextPosition *left,
		     XmTextPosition *right);

static void FindPrevWord(XmTextFieldWidget tf,
			 XmTextPosition *left,
			 XmTextPosition *right);

static void FindNextWord(XmTextFieldWidget tf,
			 XmTextPosition *left,
			 XmTextPosition *right);

static void CheckDisjointSelection(Widget w,
				   XmTextPosition position,
				   Time sel_time);

static Boolean NeedsPendingDelete(XmTextFieldWidget tf);

static Boolean NeedsPendingDeleteDisjoint(XmTextFieldWidget tf);

static void InsertChar(Widget w,
		       XEvent *event,
		       char **params,
		       Cardinal *num_params);

static void DeletePrevChar(Widget w,
			   XEvent *event,
			   char **params,
			   Cardinal *num_params);

static void DeleteNextChar(Widget w,
			   XEvent *event,
			   char **params,
			   Cardinal *num_params);

static void DeletePrevWord(Widget w,
			   XEvent *event,
			   char **params,
			   Cardinal *num_params);

static void DeleteNextWord(Widget w,
			   XEvent *event,
			   char **params,
			   Cardinal *num_params);

static void DeleteToEndOfLine(Widget w,
			      XEvent *event,
			      char **params,
			      Cardinal *num_params);

static void DeleteToStartOfLine(Widget w,
				XEvent *event,
				char **params,
				Cardinal *num_params);

static void ProcessCancel(Widget w,
			  XEvent *event,
			  char **params,
			  Cardinal *num_params);

static void Activate(Widget w,
		     XEvent *event,
		     char **params,
		     Cardinal *num_params);

static void SetAnchorBalancing(XmTextFieldWidget tf,
			       XmTextPosition position);

static void SetNavigationAnchor(XmTextFieldWidget tf,
				XmTextPosition old_position,
				XmTextPosition new_position,
#if NeedWidePrototypes
				int extend);
#else
                                Boolean extend);
#endif /* NeedWidePrototypes */

static void CompleteNavigation(XmTextFieldWidget tf,
			       XEvent *event,
			       XmTextPosition position,
			       Time time,
#if NeedWidePrototypes
			       int extend);
#else
                               Boolean extend);
#endif /* NeedWidePrototypes */

static void SimpleMovement(Widget w,
			   XEvent *event,
			   String *params,
			   Cardinal *num_params,
			   XmTextPosition cursorPos,
			   XmTextPosition position);

static void BackwardChar(Widget w,
			 XEvent *event,
			 char **params,
			 Cardinal *num_params);

static void ForwardChar(Widget w,
                        XEvent *event,
                        char **params,
                        Cardinal *num_params);

static void BackwardWord(Widget w,
			 XEvent *event,
			 char **params,
			 Cardinal *num_params);

static void ForwardWord(Widget w,
                        XEvent *event,
                        char **params,
                        Cardinal *num_params);

static void EndOfLine(Widget w,
		      XEvent *event,
		      char **params,
		      Cardinal *num_params);

static void BeginningOfLine(Widget w,
			    XEvent *event,
			    char **params,
			    Cardinal *num_params);

static void SetSelection(XmTextFieldWidget tf,
			 XmTextPosition left,
			 XmTextPosition right,
#if NeedWidePrototypes
			 int redisplay);
#else
                         Boolean redisplay);
#endif /* NeedWidePrototypes */

static void ProcessHorizontalParams(Widget w,
				    XEvent *event,
				    char **params,
				    Cardinal *num_params,
				    XmTextPosition *left,
				    XmTextPosition *right,
				    XmTextPosition *position);

static void ProcessSelectParams(Widget w,
				XEvent *event,
				XmTextPosition *left,
				XmTextPosition *right,
				XmTextPosition *position);

static void KeySelection(Widget w,
			 XEvent *event,
			 char **params,
			 Cardinal *num_params);

static void TextFocusIn(Widget w,
                        XEvent *event,
                        char **params,
                        Cardinal *num_params);

static void TextFocusOut(Widget w,
			 XEvent *event,
			 char **params,
			 Cardinal *num_params);

static void SetScanIndex(XmTextFieldWidget tf,
			 XEvent *event);

static void ExtendScanSelection(XmTextFieldWidget tf,
				XEvent *event);

static void SetScanSelection(XmTextFieldWidget tf,
			     XEvent *event);

static void StartPrimary(Widget w,
			 XEvent *event,
			 char **params,
			 Cardinal *num_params);

static void MoveDestination(Widget w,
			    XEvent *event,
			    char **params,
			    Cardinal *num_params);

static void ExtendPrimary(Widget w,
			  XEvent *event,
			  char **params,
			  Cardinal *num_params);

static void ExtendEnd(Widget w,
		      XEvent *event,
		      char **params,
		      Cardinal *num_params);

static void DoExtendedSelection(Widget w,
				Time time);

static void DoSecondaryExtend(Widget w,
			      Time ev_time);

static void BrowseScroll(XtPointer closure,
			 XtIntervalId *id);

static Boolean CheckTimerScrolling(Widget w,
				   XEvent *event);

static void RestorePrimaryHighlight(XmTextFieldWidget tf,
				    XmTextPosition prim_left,
				    XmTextPosition prim_right);

static void StartDrag(Widget w,
		      XEvent *event,
		      String *params,
		      Cardinal *num_params);

static void DragStart(XtPointer data,
		      XtIntervalId *id);

static void StartSecondary(Widget w,
			   XEvent *event,
			   char **params,
			   Cardinal *num_params);

static void ProcessBDrag(Widget w,
			 XEvent *event,
			 char **params,
			 Cardinal *num_params);

static void ProcessBDragEvent(Widget w,
			       XEvent *event,
			       char **params,
			       Cardinal *num_params);

static void ProcessBDragRelease(Widget w,
				XEvent *event,
				String *params,
				Cardinal *num_params);

static Boolean InSelection(Widget w,
			   XEvent *event);

static void ProcessBSelect(Widget w,
			   XEvent *event,
			   char **params,
			   Cardinal *num_params);

static void ProcessBSelectEvent(Widget w,
				XEvent *event,
				char **params,
				Cardinal *num_params);

static void ExtendSecondary(Widget w,
			    XEvent *event,
			    char **params,
			    Cardinal *num_params);

static void Stuff(Widget w,
		  XEvent *event,
		  char **params,
		  Cardinal *num_params);

static void SecondaryNotify(Widget w,
			    XEvent *event,
			    char **params,
			    Cardinal *num_params);

static void ProcessCopy(Widget w,
                        XEvent *event,
                        char **params,
                        Cardinal *num_params);

static void ProcessLink(Widget w,
                        XEvent *event,
                        char **params,
                        Cardinal *num_params);

static void ProcessMove(Widget w,
                        XEvent *event,
                        char **params,
                        Cardinal *num_params);

static void DeleteSelection(Widget w,
			    XEvent *event,
			    char **params,
			    Cardinal *num_params);

static void ClearSelection(Widget w,
			   XEvent *event,
			   char **params,
			   Cardinal *num_params);

static void PageRight(Widget w,
		      XEvent *event,
		      char **params,
		      Cardinal *num_params);

static void PageLeft(Widget w,
		     XEvent *event,
		     char **params,
		     Cardinal *num_params);

static void CopyPrimary(Widget w,
                        XEvent *event,
                        char **params,
                        Cardinal *num_params);

static void CutPrimary(Widget w,
		       XEvent *event,
		       char **params,
		       Cardinal *num_params);

static void LinkPrimary(Widget w,
		       XEvent *event,
		       char **params,
		       Cardinal *num_params);

static void SetAnchor(Widget w,
		      XEvent *event,
		      char **params,
		      Cardinal *num_params);

static void ToggleOverstrike(Widget w,
			     XEvent *event,
			     char **params,
			     Cardinal *num_params);

static void ToggleAddMode(Widget w,
			  XEvent *event,
			  char **params,
			  Cardinal *num_params);

static void SelectAll(Widget w,
		      XEvent *event,
		      char **params,
		      Cardinal *num_params);

static void DeselectAll(Widget w,
                        XEvent *event,
                        char **params,
                        Cardinal *num_params);

static void VoidAction(Widget w,
		       XEvent *event,
		       char **params,
		       Cardinal *num_params);

static void CutClipboard(Widget w,
			 XEvent *event,
			 char **params,
			 Cardinal *num_params);

static void CopyClipboard(Widget w,
			  XEvent *event,
			  char **params,
			  Cardinal *num_params);

static void PasteClipboard(Widget w,
			   XEvent *event,
			   char **params,
			   Cardinal *num_params);

static void TraverseDown(Widget w,
			 XEvent *event,
			 char **params,
			 Cardinal *num_params);

static void TraverseUp(Widget w,
		       XEvent *event,
		       char **params,
		       Cardinal *num_params);

static void TraverseHome(Widget w,
			 XEvent *event,
			 char **params,
			 Cardinal *num_params);

static void TraverseNextTabGroup(Widget w,
				 XEvent *event,
				 char **params,
				 Cardinal *num_params);

static void TraversePrevTabGroup(Widget w,
				 XEvent *event,
				 char **params,
				 Cardinal *num_params);

static void TextEnter(Widget w,
		      XEvent *event,
		      String *params,
		      Cardinal *num_params);

static void TextLeave(Widget w,
		      XEvent *event,
		      String *params,
		      Cardinal *num_params);

static void ClassInitialize(void);

static void ClassPartInitialize(WidgetClass w_class);

static void Validates(XmTextFieldWidget tf);

static Boolean LoadFontMetrics(XmTextFieldWidget tf);

static void ValidateString(XmTextFieldWidget tf,
			   char *value,
#if NeedWidePrototypes
			   int is_wchar);
#else
                           Boolean is_wchar);
#endif /* NeedWidePrototypes */

static void InitializeTextStruct(XmTextFieldWidget tf);

static void LoadGCs(XmTextFieldWidget tf,
		    Pixel background,
		    Pixel foreground);

static void MakeIBeamOffArea(XmTextFieldWidget tf,
#if NeedWidePrototypes
			     int width,
			     int height);
#else
                             Dimension width,
                             Dimension height);
#endif /* NeedWidePrototypes */

static Pixmap FindPixmap(Screen *screen,
			 char *image_name,
			 Pixel foreground,
			 Pixel background,
			 int depth);

static void MakeIBeamStencil(XmTextFieldWidget tf,
			     int line_width);

static void MakeAddModeCursor(XmTextFieldWidget tf,
			      int line_width);

static void MakeCursors(XmTextFieldWidget tf);

static void DragProcCallback(Widget w,
			     XtPointer client,
			     XtPointer call);

static void RegisterDropSite(Widget w);

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

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

static void Destroy(Widget wid);

static void Resize(Widget w);

static XtGeometryResult QueryGeometry(Widget w,
				      XtWidgetGeometry *intended,
				      XtWidgetGeometry *reply);

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

static Boolean SetValues(Widget old,
			 Widget request,
			 Widget new_w,
			 ArgList args,
			 Cardinal *num_args);

static Boolean TextFieldGetBaselines(Widget w,
				     Dimension **baselines,
				     int *line_count);

static Boolean TextFieldGetDisplayRect(Widget w,
				       XRectangle *display_rect);

static void TextFieldMarginsProc(Widget w,
				 XmBaselineMargins *margins_rec);

static XtPointer TextFieldGetValue(Widget w, 
				   int format);

static void TextFieldSetValue(Widget w, 
			      XtPointer s, 
			      int format);

static int TextFieldPreferredValue(Widget w);

static void CheckSetRenderTable(Widget wid,
				int offset,
				XrmValue *value); 

static Boolean TextFieldRemove(Widget w,
			       XEvent *event);
static void TextFieldReplace(Widget w,
			     XmTextPosition from_pos,
			     XmTextPosition to_pos,
			     char *value, 
			     int is_wc);
static void CursorPosVisDefault( 
                        Widget widget,
                        int offset,
                        XrmValue *value) ;

static int PreeditStart(XIC xic,
                        XPointer client_data,
                        XPointer call_data);

static void PreeditDone(XIC xic,
                        XPointer client_data,
                        XPointer call_data);

static void PreeditDraw(XIC xic,
                        XPointer client_data,
                        XIMPreeditDrawCallbackStruct *call_data);

static void PreeditCaret(XIC xic,
                         XPointer client_data,
                         XIMPreeditCaretCallbackStruct *call_data);

static void PreeditSetCursorPosition(XmTextFieldWidget tf,
                                     XmTextPosition position);

static void TextFieldResetIC(Widget w);
static void doSetHighlight(Widget w, XmTextPosition left, XmTextPosition right,
                         XmHighlightMode mode) ;
static Boolean TrimHighlights(XmTextFieldWidget tf, int *low, int *high);

/********    End Static Function Declarations    ********/

static XmConst XmTextScanType sarray[] = {
  XmSELECT_POSITION, XmSELECT_WORD, XmSELECT_LINE
};

static XContext _XmTextFDestContext = 0;

/* default translations and action recs */
static XtActionsRec text_actions[] = {
/* Text Replacing Bindings */
  {"self-insert",		InsertChar},
  {"delete-previous-character",	DeletePrevChar},
  {"delete-next-character",	DeleteNextChar},
  {"delete-previous-word",	DeletePrevWord},
  {"delete-next-word",		DeleteNextWord},
  {"delete-to-end-of-line",	DeleteToEndOfLine},
  {"delete-to-start-of-line",	DeleteToStartOfLine},
/* Miscellaneous Bindings */
  {"activate",			Activate},
  {"process-cancel",		ProcessCancel},
  {"process-bdrag",		ProcessBDrag},
  {"process-bdrag-event",	ProcessBDragEvent},
  {"process-bselect",		ProcessBSelect},
  {"process-bselect-event",	ProcessBSelectEvent},
/* Motion Bindings */
  {"backward-character",	BackwardChar},
  {"forward-character",		ForwardChar},
  {"backward-word",		BackwardWord},
  {"forward-word",		ForwardWord},
  {"end-of-line",		EndOfLine},
  {"beginning-of-line",		BeginningOfLine},
  {"page-left",			PageLeft},
  {"page-right",		PageRight},
/* Selection Bindings */
  {"key-select",		KeySelection},
  {"grab-focus",		StartPrimary},
  {"move-destination",		MoveDestination},
  {"extend-start",		ExtendPrimary},
  {"extend-adjust",		ExtendPrimary},
  {"extend-end",		ExtendEnd},
  {"delete-selection",		DeleteSelection},
  {"clear-selection",		ClearSelection},
  {"cut-primary",		CutPrimary},
  {"link-primary",		LinkPrimary},
  {"copy-primary",		CopyPrimary},
  {"set-anchor",		SetAnchor},
  {"toggle-overstrike",		ToggleOverstrike},
  {"toggle-add-mode",		ToggleAddMode},
  {"select-all",		SelectAll},
  {"deselect-all",		DeselectAll},
/* Quick Cut and Paste Bindings */
  {"secondary-start",		StartSecondary},
  {"secondary-adjust",		ExtendSecondary},
  {"copy-to",			ProcessCopy},
  {"link-to",			ProcessLink},
  {"move-to",			ProcessMove},
  {"quick-cut-set",		VoidAction},
  {"quick-copy-set",		VoidAction},
  {"do-quick-action",		VoidAction},
/* Clipboard Bindings */
  {"cut-clipboard",		CutClipboard},
  {"copy-clipboard",		CopyClipboard},
  {"paste-clipboard",		PasteClipboard},
/* Traversal */
  {"traverse-next",		TraverseDown},
  {"traverse-prev",		TraverseUp},
  {"traverse-home",		TraverseHome},
  {"next-tab-group",		TraverseNextTabGroup},
  {"prev-tab-group",		TraversePrevTabGroup},
/* Focus */
  {"focusIn",			TextFocusIn},
  {"focusOut",			TextFocusOut},
  {"enter",			TextEnter},
  {"leave",			TextLeave},
};

static XtResource resources[] =
{
  {
    XmNactivateCallback, XmCCallback, XmRCallback, sizeof(XtCallbackList),
    XtOffsetOf(struct _XmTextFieldRec, text.activate_callback),
    XmRCallback, NULL
  },

  {
    XmNlosingFocusCallback, XmCCallback, XmRCallback, sizeof(XtCallbackList),
    XtOffsetOf(struct _XmTextFieldRec, text.losing_focus_callback),
    XmRCallback, NULL
  },

  {
    XmNfocusCallback, XmCCallback, XmRCallback, sizeof(XtCallbackList),
    XtOffsetOf(struct _XmTextFieldRec, text.focus_callback),
    XmRCallback, NULL
  },

  {
    XmNmodifyVerifyCallback, XmCCallback, XmRCallback,
    sizeof(XtCallbackList),
    XtOffsetOf(struct _XmTextFieldRec, text.modify_verify_callback),
    XmRCallback, NULL
  },

  {
    XmNmodifyVerifyCallbackWcs, XmCCallback, XmRCallback,
    sizeof(XtCallbackList),
    XtOffsetOf(struct _XmTextFieldRec, text.wcs_modify_verify_callback),
    XmRCallback, NULL
  },

  {
    XmNmotionVerifyCallback, XmCCallback, XmRCallback,
    sizeof(XtCallbackList),
    XtOffsetOf(struct _XmTextFieldRec, text.motion_verify_callback),
    XmRCallback, NULL
  },

  {
    XmNgainPrimaryCallback, XmCCallback, XmRCallback, sizeof(XtCallbackList),
    XtOffsetOf(struct _XmTextFieldRec, text.gain_primary_callback),
    XmRCallback, NULL
  },

  {
    XmNlosePrimaryCallback, XmCCallback, XmRCallback, sizeof(XtCallbackList),
    XtOffsetOf(struct _XmTextFieldRec, text.lose_primary_callback),
    XmRCallback, NULL
  },

  {
    XmNvalueChangedCallback, XmCCallback, XmRCallback,
    sizeof(XtCallbackList),
    XtOffsetOf(struct _XmTextFieldRec, text.value_changed_callback),
    XmRCallback, NULL
  },

  {
    XmNdestinationCallback, XmCCallback, XmRCallback, sizeof(XtCallbackList),
    XtOffsetOf(struct _XmTextFieldRec, text.destination_callback),
    XmRCallback, NULL
  },

  {
    XmNvalue, XmCValue, XmRString, sizeof(String),
    XtOffsetOf(struct _XmTextFieldRec, text.value),
    XmRString, ""
  },

  {
    XmNvalueWcs, XmCValueWcs, XmRValueWcs, sizeof(wchar_t*),
    XtOffsetOf(struct _XmTextFieldRec, text.wc_value),
    XmRString, NULL
  },

  {
    XmNmarginHeight, XmCMarginHeight, XmRVerticalDimension,
    sizeof(Dimension),
    XtOffsetOf(struct _XmTextFieldRec, text.margin_height),
    XmRImmediate, (XtPointer) 5
  },

  {
    XmNmarginWidth, XmCMarginWidth, XmRHorizontalDimension,
    sizeof(Dimension),
    XtOffsetOf(struct _XmTextFieldRec, text.margin_width),
    XmRImmediate, (XtPointer) 5
  },

  {
    XmNcursorPosition, XmCCursorPosition, XmRTextPosition,
    sizeof (XmTextPosition),
    XtOffsetOf(struct _XmTextFieldRec, text.cursor_position),
    XmRImmediate, (XtPointer) 0
  },

  {
    XmNcolumns, XmCColumns, XmRShort, sizeof(short),
    XtOffsetOf(struct _XmTextFieldRec, text.columns),
    XmRImmediate, (XtPointer) 20
  },

  {
    XmNmaxLength, XmCMaxLength, XmRInt, sizeof(int),
    XtOffsetOf(struct _XmTextFieldRec, text.max_length),
    XmRImmediate, (XtPointer) INT_MAX
  },

  {
    XmNblinkRate, XmCBlinkRate, XmRInt, sizeof(int),
    XtOffsetOf(struct _XmTextFieldRec, text.blink_rate),
    XmRImmediate, (XtPointer) 500
  },

  {
      "pri.vate","Pri.vate",XmRBoolean,
      sizeof(Boolean), XtOffsetOf(struct _XmTextFieldRec,
	  text.check_set_render_table),
	  XmRImmediate, (XtPointer) False
  },

  {
    XmNfontList, XmCFontList, XmRFontList, sizeof(XmFontList),
    XtOffsetOf(struct _XmTextFieldRec, text.font_list),
    XmRCallProc, (XtPointer)CheckSetRenderTable
  },

  {
    XmNrenderTable, XmCRenderTable, XmRRenderTable, sizeof(XmRenderTable),
    XtOffsetOf(struct _XmTextFieldRec, text.font_list),
    XmRCallProc, (XtPointer)CheckSetRenderTable
  },

  {
    XmNselectionArray, XmCSelectionArray, XmRPointer,
    sizeof(XtPointer),
    XtOffsetOf(struct _XmTextFieldRec, text.selection_array),
    XmRImmediate, (XtPointer) sarray
  },

  {
    XmNselectionArrayCount, XmCSelectionArrayCount, XmRInt, sizeof(int),
    XtOffsetOf(struct _XmTextFieldRec, text.selection_array_count),
    XmRImmediate, (XtPointer) XtNumber(sarray)
  },

  {
    XmNresizeWidth, XmCResizeWidth, XmRBoolean, sizeof(Boolean),
    XtOffsetOf(struct _XmTextFieldRec, text.resize_width),
    XmRImmediate, (XtPointer) False
  },

  {
    XmNpendingDelete, XmCPendingDelete, XmRBoolean, sizeof(Boolean),
    XtOffsetOf(struct _XmTextFieldRec, text.pending_delete),
    XmRImmediate, (XtPointer) True
  },

  {
    XmNeditable, XmCEditable, XmRBoolean, sizeof(Boolean),
    XtOffsetOf(struct _XmTextFieldRec, text.editable),
    XmRImmediate, (XtPointer) True
  },

  {
    XmNcursorPositionVisible, XmCCursorPositionVisible, XmRBoolean,
    sizeof(Boolean),
    XtOffsetOf(struct _XmTextFieldRec, text.cursor_position_visible),
    XmRCallProc, (XtPointer) CursorPosVisDefault
  },

 {
   XmNverifyBell, XmCVerifyBell, XmRBoolean, sizeof(Boolean),
   XtOffsetOf(struct _XmTextFieldRec, text.verify_bell),
   XmRImmediate, (XtPointer) XmDYNAMIC_BOOL
 },

 {
   XmNselectThreshold, XmCSelectThreshold, XmRInt, sizeof(int),
   XtOffsetOf(struct _XmTextFieldRec, text.threshold),
   XmRImmediate, (XtPointer) 5
 },

 {
   XmNnavigationType, XmCNavigationType, XmRNavigationType,
   sizeof (unsigned char),
   XtOffsetOf(struct _XmPrimitiveRec, primitive.navigation_type),
   XmRImmediate, (XtPointer) XmTAB_GROUP
 }
};

/* Definition for resources that need special processing in get values */

static XmSyntheticResource syn_resources[] =
{
 {
   XmNmarginWidth,
   sizeof(Dimension),
   XtOffsetOf(struct _XmTextFieldRec, text.margin_width),
   XmeFromHorizontalPixels,
   XmeToHorizontalPixels
 },

 {
   XmNmarginHeight,
   sizeof(Dimension),
   XtOffsetOf(struct _XmTextFieldRec, text.margin_height),
   XmeFromVerticalPixels,
   XmeToVerticalPixels
 },

 {
   XmNvalue,
   sizeof(char *),
   XtOffsetOf(struct _XmTextFieldRec, text.value),
   MakeCopy,
 },

 {
   XmNvalueWcs,
   sizeof(wchar_t *),
   XtOffsetOf(struct _XmTextFieldRec, text.wc_value),
   WcsMakeCopy,
 }

};

static XmPrimitiveClassExtRec _XmTextFPrimClassExtRec = {
  NULL,
  NULLQUARK,
  XmPrimitiveClassExtVersion,
  sizeof(XmPrimitiveClassExtRec),
  TextFieldGetBaselines,                  /* widget_baseline */
  TextFieldGetDisplayRect,               /* widget_display_rect */
  TextFieldMarginsProc,                  /* get/set widget margins */
};


externaldef(xmtextfieldclassrec) XmTextFieldClassRec xmTextFieldClassRec =
{
  {
    (WidgetClass) &xmPrimitiveClassRec,		/* superclass         */
    "XmTextField",				/* class_name         */
    sizeof(XmTextFieldRec),		        /* widget_size        */
    ClassInitialize,				/* class_initialize   */
    ClassPartInitialize,			/* class_part_initiali*/
    FALSE,					/* class_inited       */
    Initialize,					/* initialize         */
    (XtArgsProc)NULL,				/* initialize_hook    */
    Realize,					/* realize            */
    text_actions,				/* actions            */
    XtNumber(text_actions),			/* num_actions        */
    resources,					/* resources          */
    XtNumber(resources),			/* num_resources      */
    NULLQUARK,					/* xrm_class          */
    TRUE,					/* compress_motion    */
    XtExposeCompressMaximal |			/* compress_exposure  */
      XtExposeNoRegion,
    TRUE,					/* compress_enterleave*/
    FALSE,					/* visible_interest   */
    Destroy,					/* destroy            */
    Resize,					/* resize             */
    TextFieldExpose,				/* expose             */
    SetValues,					/* set_values         */
    (XtArgsFunc)NULL,				/* set_values_hook    */
    XtInheritSetValuesAlmost,			/* set_values_almost  */
    (XtArgsProc)NULL,				/* get_values_hook    */
    (XtAcceptFocusProc)NULL,			/* accept_focus       */
    XtVersion,					/* version            */
    NULL,					/* callback_private   */
    NULL,					/* tm_table           */
    QueryGeometry,				/* query_geometry     */
    (XtStringProc)NULL,				/* display accel      */
    NULL,					/* extension          */
  },
  
  {	                          		/* Xmprimitive        */
    XmInheritBorderHighlight,        		/* border_highlight   */
    XmInheritBorderUnhighlight,              	/* border_unhighlight */
    NULL,					/* translations	      */
    (XtActionProc)NULL,             		/* arm_and_activate   */
    syn_resources,            			/* syn resources      */
    XtNumber(syn_resources),  			/* num syn_resources  */
    (XtPointer) &_XmTextFPrimClassExtRec,	/* extension          */
  },
  
  {                         			/* text class         */
    NULL,                     			/* extension          */
  }
};

externaldef(xmtextfieldwidgetclass) WidgetClass xmTextFieldWidgetClass =
					 (WidgetClass) &xmTextFieldClassRec;

/* AccessXmString Trait record for TextField */
static XmConst XmAccessTextualTraitRec textFieldCS = {
  0,  				/* version */
  TextFieldGetValue,
  TextFieldSetValue,
  TextFieldPreferredValue,
};

static void 
ClassInitialize(void)
{
  _XmTextFieldInstallTransferTrait();
  XmeTraitSet((XtPointer)xmTextFieldWidgetClass, XmQTaccessTextual, 
	      (XtPointer) &textFieldCS);
}

/*********************************************************************
 *
 * CursorPosVisDefault
 *    
 *
 *********************************************************************/
/*ARGSUSED*/
static void 
CursorPosVisDefault(
        Widget widget,
        int offset,		/* unused */
        XrmValue *value )
{
      static Boolean cursor_pos_vis ;
      Widget print_shell ;

      value->addr = (XPointer) &cursor_pos_vis;
              
      print_shell = widget ;
      while(print_shell && !XmIsPrintShell(print_shell)) 
	  print_shell = XtParent(print_shell);    

      if (print_shell) cursor_pos_vis = False ;
      else             cursor_pos_vis = True ;
}


/* USE ITERATIONS OF mblen TO COUNT THE NUMBER OF CHARACTERS REPRESENTED
 * BY n_bytes BYTES POINTED TO BY ptr, a pointer to char*.
 * n_bytes does not include NULL terminator (if any), nor does return.
 */
/* ARGSUSED */
int
_XmTextFieldCountCharacters(XmTextFieldWidget tf,
			    char *ptr,
			    int n_bytes)
{
  char * bptr;
  int count = 0;
#ifndef NO_MULTIBYTE
  int char_size = 0;
#else
  int char_size = 1;
#endif
  
  if (n_bytes <= 0 || ptr == NULL || *ptr == '\0')
    return 0;
  
  if (tf->text.max_char_size == 1)
    return n_bytes;
  
  bptr = ptr;
  
#ifndef NO_MULTIBYTE
  for (bptr = ptr; n_bytes > 0; count++, bptr+= char_size) {
    char_size = mblen(bptr, tf->text.max_char_size);
    if (char_size <= 0) break; /* error */
    n_bytes -= char_size;
  }
#else
  while (*bptr++ && n_bytes--)
    count++;
#endif
  return count;
}

/* USE ITERATIONS OF wctomb TO COUNT THE NUMBER OF BYTES REQUIRED FOR THE
 * MULTI-BYTE REPRESENTION OF num_chars WIDE CHARACTERS IN wc_value.
 * COUNT TERMINATED IF NULL ENCOUNTERED IN THE STRING.
 * NUMBER OF BYTES IS RETURNED.
 */
/* ARGSUSED */
int
_XmTextFieldCountBytes(XmTextFieldWidget tf,
		       wchar_t * wc_value, 
		       int num_chars)
{
  wchar_t 	* wc_ptr;
  char 	tmp[MB_LEN_MAX];  /* defined in limits.h: max in any locale */
  int 	n_bytes = 0;
  int   n_bytes_per_char = 0;
  
  if (num_chars <= 0 || wc_value == NULL || *wc_value == (wchar_t)0L)
    return 0;
  
  if (tf->text.max_char_size == 1)
    return num_chars;
  
  wc_ptr = wc_value;
  while ((num_chars > 0) && (*wc_ptr != (wchar_t)0L)) {
    n_bytes_per_char = wctomb(tmp, *wc_ptr);
    if (n_bytes_per_char > 0 )
      n_bytes += n_bytes_per_char;
    num_chars--;
    wc_ptr++;
  }
  return n_bytes;
}

/*ARGSUSED*/
static void 
MakeCopy(Widget w,
	 int n,
	 XtArgVal *value)
{
  (*value) = (XtArgVal) XmTextFieldGetString (w);
}

/*ARGSUSED*/
static void 
WcsMakeCopy(Widget w,
	    int n,
	    XtArgVal *value)
{
  (*value) = (XtArgVal) XmTextFieldGetStringWcs (w);
}

/*ARGSUSED*/
static void
FreeContextData(Widget w,		/* unused */
		XtPointer clientData,
		XtPointer callData)	/* unused */
{
  XmTextContextData ctx_data = (XmTextContextData) clientData;
  Display *display = DisplayOfScreen(ctx_data->screen);
  XtPointer data_ptr;
  
  if (XFindContext(display, (Window) ctx_data->screen,
		   ctx_data->context, (char **) &data_ptr)) {
    
    if (ctx_data->type != '\0') {
      if (data_ptr)
	XtFree((char *) data_ptr);
    }
    
    XDeleteContext (display, (Window) ctx_data->screen, ctx_data->context);
  }
  
  XtFree ((char *) ctx_data);
}

static TextFDestData 
GetTextFDestData(Widget w)
{
  TextFDestData dest_data;
  Display *display = XtDisplay(w);
  Screen *screen = XtScreen(w);
  XContext loc_context;

  _XmProcessLock();
  if (_XmTextFDestContext == 0)
    _XmTextFDestContext = XUniqueContext();
  loc_context = _XmTextFDestContext;
  _XmProcessUnlock();
 
  if (XFindContext(display, (Window) screen,
		   loc_context, (char **) &dest_data)) {
    XmTextContextData ctx_data;
    Widget xm_display = (Widget) XmGetXmDisplay(display);

    ctx_data = (XmTextContextData) XtMalloc(sizeof(XmTextContextDataRec));

    ctx_data->screen = screen;
    ctx_data->context = loc_context;
    ctx_data->type = _XM_IS_DEST_CTX;

    dest_data = (TextFDestData) XtCalloc((unsigned)sizeof(TextFDestDataRec),
					 (unsigned) 1);
    
    XtAddCallback(xm_display, XmNdestroyCallback, 
		  (XtCallbackProc) FreeContextData, (XtPointer) ctx_data);
    
    XSaveContext(XtDisplay(w), (Window) screen,
		 loc_context, (XPointer)dest_data);
  }
  
  return dest_data;
}

void
_XmTextFToggleCursorGC(Widget widget)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) widget;
  XGCValues values;
  unsigned long valueMask;
  Pixmap stipple = XmUNSPECIFIED_PIXMAP;
  
  SetFullGC(tf, tf->text.image_gc);
  ResetClipOrigin(tf);
  
  if (!XtIsRealized(widget)) return;
  
  if (tf->text.overstrike) {
    valueMask = GCFillStyle|GCFunction|GCForeground|GCBackground;
    if (!tf->text.add_mode && XtIsSensitive(widget) &&
	(tf->text.has_focus || tf->text.has_destination)) {
      values.fill_style = FillSolid;
    } else {
      valueMask |= GCStipple;
      values.fill_style = FillStippled;
      values.stipple = tf->text.stipple_tile;
    }
    values.foreground = values.background =
      tf->primitive.foreground ^ tf->core.background_pixel;
    values.function = GXxor;
  } else {
    valueMask = GCStipple;
    if (XGetGCValues(XtDisplay(widget), tf->text.image_gc, 
		     valueMask, &values))
      stipple = values.stipple;
    valueMask = GCFillStyle|GCFunction|GCForeground|GCBackground;
    if (XtIsSensitive(widget) && !tf->text.add_mode &&
	(tf->text.has_focus || tf->text.has_destination)) {
      if (tf->text.cursor == XmUNSPECIFIED_PIXMAP) return;
      if (stipple != tf->text.cursor) {
	values.stipple = tf->text.cursor;
	valueMask |= GCStipple;
      }
    } else {
      if (tf->text.add_mode_cursor == XmUNSPECIFIED_PIXMAP) return;
      if (stipple != tf->text.add_mode_cursor) {
	values.stipple = tf->text.add_mode_cursor;
	valueMask |= GCStipple;
      }
    }
    values.fill_style = FillStippled;
    values.function = GXcopy;
    if (tf->text.have_inverted_image_gc) {
      values.background = tf->primitive.foreground;
      values.foreground = tf->core.background_pixel;
    } else {
      values.foreground = tf->primitive.foreground;
      values.background = tf->core.background_pixel;
    }
  }
  XSetClipMask(XtDisplay(widget), tf->text.save_gc, None);
  XChangeGC(XtDisplay(widget), tf->text.image_gc, valueMask, &values);
}

/*
 * Find the highlight record corresponding to the given position.  Returns a
 * pointer to the record.  The third argument indicates whether we are probing
 * the left or right edge of a highlighting range.
 */
static _XmHighlightRec * 
FindHighlight(XmTextFieldWidget w,
	      XmTextPosition position)
{
  _XmHighlightRec *l = w->text.highlight.list;
  int i;
  
  for (i=w->text.highlight.number - 1; i>=0; i--)
    if (position >= l[i].position) {
      l = l + i;
      break;
    }
  
  return(l);
}

static void 
InsertHighlight(XmTextFieldWidget w,
		XmTextPosition position,
		XmHighlightMode mode)
{
  _XmHighlightRec *l1;
  _XmHighlightRec *l = w->text.highlight.list;
  int i, j;
  
  l1 = FindHighlight(w, position);
  if (l1->position == position)
    l1->mode = mode;
  else {
    i = (l1 - l) + 1;
    w->text.highlight.number++;
    if (w->text.highlight.number > w->text.highlight.maximum) {
      w->text.highlight.maximum = w->text.highlight.number;
      l = w->text.highlight.list = (_XmHighlightRec *)
	XtRealloc((char *) l, (unsigned)(w->text.highlight.maximum *
					 sizeof(_XmHighlightRec)));
    }
    for (j=w->text.highlight.number-1; j>i; j--)
      l[j] = l[j-1];
    l[i].position = position;
    l[i].mode = mode;
  }
}

static void 
TextFieldSetHighlight(XmTextFieldWidget tf,
		      XmTextPosition left,
		      XmTextPosition right,
		      XmHighlightMode mode)
{
  _XmHighlightRec *l;
  XmHighlightMode endmode;
  int i, j;
  
  if (left >= right || right <= 0) return;
  
  _XmTextFieldDrawInsertionPoint(tf, False);
  endmode = FindHighlight(tf, right)->mode;
  InsertHighlight(tf, left, mode);
  InsertHighlight(tf, right, endmode);
  l = tf->text.highlight.list;
  i = 1;
  while (i < tf->text.highlight.number) {
    if (l[i].position >= left && l[i].position < right)
      l[i].mode = mode;
    if (l[i].mode == l[i-1].mode) {
      tf->text.highlight.number--;
      for (j=i; j<tf->text.highlight.number; j++)
	l[j] = l[j+1];
    } else i++;
  }
  if (TextF_CursorPosition(tf) > left && TextF_CursorPosition(tf) < right) {
    if (mode == XmHIGHLIGHT_SELECTED) {
      InvertImageGC(tf);
    } else if (mode != XmHIGHLIGHT_SELECTED) {
      ResetImageGC(tf);
    }
  }
  tf->text.refresh_ibeam_off = True;
  _XmTextFieldDrawInsertionPoint(tf, True);
}

/*
 * Get x and y based on position.
 */
static Boolean 
GetXYFromPos(XmTextFieldWidget tf,
	     XmTextPosition position,
	     Position *x,
	     Position *y)
{
  /* initialize the x and y positions to zero */
  *x = 0;
  *y = 0;
  
  if (position > tf->text.string_length) return False;
  
  if (tf->text.max_char_size != 1) {
    *x += FindPixelLength(tf, (char*)TextF_WcValue(tf), (int)position);
  } else {
    *x += FindPixelLength(tf, TextF_Value(tf), (int)position);
  }
  
  *y += tf->primitive.highlight_thickness + tf->primitive.shadow_thickness
    + tf->text.margin_top + TextF_FontAscent(tf);
  *x += (Position) tf->text.h_offset;
  
  return True;
}

static Boolean 
CurrentCursorState(XmTextFieldWidget tf)
{
  if (tf->text.cursor_on < 0) return False;
  if (tf->text.blink_on || !XtIsSensitive((Widget)tf))
    return True;
  return False;
}

/*
 * Paint insert cursor
 */
static void 
PaintCursor(XmTextFieldWidget tf)
{
  Position x, y;
  XmTextPosition position;
  
  if (!TextF_CursorPositionVisible(tf)) return;
  
  _XmTextFToggleCursorGC((Widget)tf);
  
  position = TextF_CursorPosition(tf);
  (void) GetXYFromPos(tf, position, &x, &y);
  
  if (!tf->text.overstrike)
    x -=(tf->text.cursor_width >> 1) + 1; /* "+1" for 1 pixel left of char */
  else {
    int pxlen;
    if (tf->text.max_char_size != 1) 
      pxlen = FindPixelLength(tf, (char*)&(TextF_WcValue(tf)[position]), 1);
    else 
      pxlen = FindPixelLength(tf, &(TextF_Value(tf)[position]), 1);
    if (pxlen > tf->text.cursor_width)
      x += (pxlen - tf->text.cursor_width) >> 1;
  }
  y = (y + (Position) TextF_FontDescent(tf)) -
    (Position) tf->text.cursor_height;
  
  /* If time to paint the I Beam... first capture the IBeamOffArea, then draw
   * the IBeam */
  
  if (tf->text.refresh_ibeam_off == True) { /* get area under IBeam first */
    /* Fill is needed to realign clip rectangle with gc */
    XFillRectangle(XtDisplay((Widget)tf), XtWindow((Widget)tf),
		   tf->text.save_gc, 0, 0, 0, 0);
    XCopyArea(XtDisplay(tf), XtWindow(tf), tf->text.ibeam_off, 
	      tf->text.save_gc, x, y, tf->text.cursor_width, 
	      tf->text.cursor_height, 0, 0);
    tf->text.refresh_ibeam_off = False;
  }
  
    /* redraw cursor, being very sure to keep it within the bounds of the 
    ** text area, not spilling into the highlight area
    */
  {
  int cursor_width = tf->text.cursor_width;
  int cursor_height = tf->text.cursor_height;
  if ((tf->text.cursor_on >= 0) && tf->text.blink_on) {
        if ((int)(x + tf->text.cursor_width) > (int)(tf->core.width -     
		 tf->primitive.shadow_thickness -   
		 tf->primitive.highlight_thickness))
          cursor_width = (tf->core.width -              
                                 (tf->primitive.shadow_thickness +          
                                 tf->primitive.highlight_thickness)) - x;   
           if ( cursor_width > 0 && cursor_height > 0 )
    		XFillRectangle(XtDisplay(tf), XtWindow(tf), tf->text.image_gc, x, y,
		   cursor_width, cursor_height);
  } else {
        Position src_x = 0;                                                     
        if ((int)(x + tf->text.cursor_width) > (int)(tf->core.width -    
                            tf->primitive.shadow_thickness -                 
                            tf->primitive.highlight_thickness)) {            
          cursor_width = (tf->core.width -               
                                 (tf->primitive.shadow_thickness +           
                                 tf->primitive.highlight_thickness)) - x;   
        }
         else if (x < (Position)(tf->primitive.highlight_thickness +                   
                                 tf->primitive.shadow_thickness)) {          
             cursor_width = tf->text.cursor_width -                                 
                                 (tf->primitive.highlight_thickness +       
                                 tf->primitive.shadow_thickness - x);        
             src_x = tf->text.cursor_width - cursor_width;                          
             x = tf->primitive.highlight_thickness +                        
                                 tf->primitive.shadow_thickness;             
         }
        if ((int)(y + tf->text.cursor_height) > (int)(tf->core.height -    
                                 (tf->primitive.highlight_thickness +        
                                 tf->primitive.shadow_thickness))) {         
          cursor_height = tf->text.cursor_height -                                   
                                 ((y + tf->text.cursor_height) -                    
                                 (tf->core.height -       
                                 (tf->primitive.highlight_thickness +        
                                 tf->primitive.shadow_thickness)));          
        }
           if (cursor_width > 0 && cursor_height > 0)
  	  	XCopyArea(XtDisplay(tf), tf->text.ibeam_off, XtWindow(tf), 
		      tf->text.save_gc, 0, 0, cursor_width, 
		      cursor_height, x, y);
  	}
  }
}

void 
_XmTextFieldDrawInsertionPoint(XmTextFieldWidget tf,
#if NeedWidePrototypes
			       int turn_on)
#else
                               Boolean turn_on)
#endif /* NeedWidePrototypes */
{
  
  if (turn_on == True) {
    tf->text.cursor_on += 1;
    if (TextF_BlinkRate(tf) == 0 || !tf->text.has_focus)
      tf->text.blink_on = True;
  } else {
    if (tf->text.blink_on && (tf->text.cursor_on == 0))
      if (tf->text.blink_on == CurrentCursorState(tf) &&
	  XtIsRealized((Widget)tf)) {
	tf->text.blink_on = !tf->text.blink_on;
	PaintCursor(tf);
      }
    tf->text.cursor_on -= 1;
  }
  
  if (tf->text.cursor_on < 0 || !XtIsRealized((Widget) tf))
    return;
  
  PaintCursor(tf);
}

static void 
BlinkInsertionPoint(XmTextFieldWidget tf)
{
  if ((tf->text.cursor_on >= 0) &&
      (tf->text.blink_on == CurrentCursorState(tf)) && 
      XtIsRealized((Widget)tf)) {
    tf->text.blink_on = !tf->text.blink_on;
    PaintCursor(tf);
  }
}



/*
 * Handle blink on and off
 */
/* ARGSUSED */
static void 
HandleTimer(XtPointer closure,
	    XtIntervalId *id)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) closure;
  
  if (TextF_BlinkRate(tf) != 0)
    tf->text.timer_id =
      XtAppAddTimeOut(XtWidgetToApplicationContext((Widget)tf),
		      (unsigned long)TextF_BlinkRate(tf),
		      HandleTimer,
		      (XtPointer) closure);
  if (tf->text.has_focus && XtIsSensitive((Widget)tf)) BlinkInsertionPoint(tf);
}


/*
 * Change state of blinking insert cursor on and off
 */
static void 
ChangeBlinkBehavior(XmTextFieldWidget tf,
#if NeedWidePrototypes
		    int turn_on)
#else
                    Boolean turn_on)
#endif /* NeedWidePrototypes */
{
  
  if (turn_on) {
    if (TextF_BlinkRate(tf) != 0 && tf->text.timer_id == (XtIntervalId)0)
      tf->text.timer_id =
	XtAppAddTimeOut(XtWidgetToApplicationContext((Widget)tf),
			(unsigned long)TextF_BlinkRate(tf),
			HandleTimer,
			(XtPointer) tf);
    tf->text.blink_on = True;
  } else {
    if (tf->text.timer_id)
      XtRemoveTimeOut(tf->text.timer_id);
    tf->text.timer_id = (XtIntervalId)0;
  }
}

static void 
GetRect(XmTextFieldWidget tf,
        XRectangle *rect)
{
  Dimension margin_width = TextF_MarginWidth(tf) +
    tf->primitive.shadow_thickness +
      tf->primitive.highlight_thickness;
  Dimension margin_top = tf->text.margin_top + tf->primitive.shadow_thickness +
    tf->primitive.highlight_thickness;
  Dimension margin_bottom = tf->text.margin_bottom +
    tf->primitive.shadow_thickness +
      tf->primitive.highlight_thickness;
  
  if (margin_width < tf->core.width)
    rect->x = margin_width;
  else
    rect->x = tf->core.width;
  
  if (margin_top  < tf->core.height)
    rect->y = margin_top;
  else
    rect->y = tf->core.height;
  
  if ((Dimension)(2 * margin_width) < tf->core.width)
    rect->width = (int) tf->core.width - (2 * margin_width);
  else
    rect->width = 0;
  
  if ((Dimension)(margin_top + margin_bottom) < tf->core.height)
    rect->height = (int) tf->core.height - (margin_top + margin_bottom);
  else
    rect->height = 0;
}

static void 
SetFullGC(XmTextFieldWidget tf,
	    GC gc)
{
  XRectangle ClipRect;
  
  /* adjust clip rectangle to allow the cursor to paint into the margins */
  ClipRect.x = tf->primitive.shadow_thickness +
    tf->primitive.highlight_thickness;
  ClipRect.y = tf->primitive.shadow_thickness +
    tf->primitive.highlight_thickness;
  ClipRect.width = tf->core.width - (2 * (tf->primitive.shadow_thickness +
                                          tf->primitive.highlight_thickness));
  ClipRect.height = tf->core.height - (2 *(tf->primitive.shadow_thickness +
					   tf->primitive.highlight_thickness));
  
  XSetClipRectangles(XtDisplay(tf), gc, 0, 0, &ClipRect, 1,
                     Unsorted);
}

static void 
SetMarginGC(XmTextFieldWidget tf,
	      GC gc)
{
  XRectangle ClipRect;
  
  GetRect(tf, &ClipRect);
  XSetClipRectangles(XtDisplay(tf), gc, 0, 0, &ClipRect, 1,
                     Unsorted);
}


/*
 * Set new clipping rectangle for text field.  This is
 * done on each focus in event since the text field widgets
 * share the same GC.
 */
void 
_XmTextFieldSetClipRect(XmTextFieldWidget tf)
{
  XGCValues values;
  unsigned long valueMask = (unsigned long) 0;
  
  SetMarginGC(tf, tf->text.gc);
  
  /* Restore cached text gc to state correct for this instantiation */
  
  if (tf->text.gc) {
    if (!TextF_UseFontSet(tf) && (TextF_Font(tf) != NULL)) {
      valueMask |= GCFont;
      values.font = TextF_Font(tf)->fid;
    }
    values.foreground = tf->primitive.foreground ^ tf->core.background_pixel;
    values.background = 0;
    XChangeGC(XtDisplay(tf), tf->text.gc, valueMask, &values);
  }
}

static void 
SetNormGC(XmTextFieldWidget tf,
	    GC gc,
#if NeedWidePrototypes
	    int change_stipple,
	    int stipple)
#else
            Boolean change_stipple,
            Boolean stipple)
#endif /* NeedWidePrototypes */
{
  unsigned long valueMask = (GCForeground | GCBackground);
  XGCValues values;
  
  _XmTextFieldSetClipRect(tf);
  values.foreground = tf->primitive.foreground;
  values.background = tf->core.background_pixel;
  
  if (change_stipple) {
    valueMask |= GCFillStyle;
    if (stipple) {
      values.fill_style = FillStippled;
      valueMask |= GCStipple;
      values.stipple = tf->text.stipple_tile;
    } else 
      values.fill_style = FillSolid;
  }
  
  XChangeGC(XtDisplay(tf), gc, valueMask, &values);
}

static void 
SetInvGC(XmTextFieldWidget tf,
	   GC gc)
{
  unsigned long valueMask = (GCForeground | GCBackground);
  XGCValues values;
  
  _XmTextFieldSetClipRect(tf);
  values.foreground = tf->core.background_pixel;
  values.background = tf->primitive.foreground;
  
  XChangeGC(XtDisplay(tf), gc, valueMask, &values);
}

static void
DrawText(XmTextFieldWidget tf,
	 GC  gc,
	 int x,
	 int y,
	 char * string,
	 int length)
{
  if (TextF_UseFontSet(tf)) {
    if (tf->text.max_char_size != 1) 
      XwcDrawString (XtDisplay(tf), XtWindow(tf), (XFontSet)TextF_Font(tf),
		     gc, x, y, (wchar_t*) string, length);
    
    else  /* one byte chars */
      XmbDrawString (XtDisplay(tf), XtWindow(tf), (XFontSet)TextF_Font(tf),
		     gc, x, y, string, length);
    
  } else { /* have a font struct, not a font set */
    if (tf->text.max_char_size != 1) { /* was passed a wchar_t*  */
      char stack_cache[400], *tmp;
      wchar_t tmp_wc;
      wchar_t *wc_string = (wchar_t*)string;
      int num_bytes = 0;
      /* ptr = tmp = XtMalloc((int)(length + 1)*sizeof(wchar_t)); */
      tmp = (char *)XmStackAlloc((Cardinal) ((length + 1)*sizeof(wchar_t)),
				 stack_cache);
      tmp_wc = wc_string[length];
      wc_string[length] = 0L;
      num_bytes = wcstombs(tmp, wc_string,
			   (int)((length + 1) * sizeof(wchar_t)));
      wc_string[length] = tmp_wc;
      if (num_bytes >= 0)
	XDrawString (XtDisplay(tf), XtWindow(tf), gc, x, y, tmp, num_bytes);
      XmStackFree(tmp, stack_cache);
    } else /* one byte chars */
      XDrawString (XtDisplay(tf), XtWindow(tf), gc, x, y, string, length);
  }
}

static int
FindPixelLength(XmTextFieldWidget tf,
		char * string,
		int length)
{
  if (TextF_UseFontSet(tf)) {
    if (tf->text.max_char_size != 1)
      return (XwcTextEscapement((XFontSet)TextF_Font(tf), 
				(wchar_t *) string, length));
    else /* one byte chars */
      return (XmbTextEscapement((XFontSet)TextF_Font(tf), string, length));
  } else { /* have font struct, not a font set */
    if (tf->text.max_char_size != 1) { /* was passed a wchar_t*  */
      wchar_t *wc_string = (wchar_t*)string;
      wchar_t wc_tmp = wc_string[length];
      char stack_cache[400], *tmp;
      int num_bytes, ret_len = 0;
      
      wc_string[length] = 0L;
      tmp = (char*)XmStackAlloc((Cardinal)((length + 1) * sizeof(wchar_t)),
				stack_cache);
      num_bytes = wcstombs(tmp, wc_string, 
			   (int)((length + 1)*sizeof(wchar_t)));
      wc_string[length] = wc_tmp;
      if (num_bytes >= 0)
	ret_len = XTextWidth(TextF_Font(tf), tmp, num_bytes);
      XmStackFree(tmp, stack_cache);
      return (ret_len);
    } else /* one byte chars */
      return (XTextWidth(TextF_Font(tf), string, length));
  }
}

static void
DrawTextSegment(XmTextFieldWidget tf,
		XmHighlightMode mode,
		XmTextPosition prev_seg_start,
		XmTextPosition seg_start,
		XmTextPosition seg_end,
		XmTextPosition next_seg,
#if NeedWidePrototypes
		int stipple,
#else
		Boolean stipple,
#endif /* NeedWidePrototypes */
		int y,
		int *x)
{
  int x_seg_len;
  
  /* update x position up to start position */
  
  if (tf->text.max_char_size != 1) {
    *x += FindPixelLength(tf, (char*)(TextF_WcValue(tf) + prev_seg_start),
			  (int)(seg_start - prev_seg_start));
    x_seg_len = FindPixelLength(tf, (char*)(TextF_WcValue(tf) + seg_start),
				(int)seg_end - (int)seg_start);
  } else {
    *x += FindPixelLength(tf, TextF_Value(tf) + prev_seg_start,
			  (int)(seg_start - prev_seg_start));
    x_seg_len = FindPixelLength(tf, TextF_Value(tf) + seg_start,
				(int)seg_end - (int)seg_start);
  }
  if (mode == XmHIGHLIGHT_SELECTED) {
    /* Draw the selected text using an inverse gc */
    SetNormGC(tf, tf->text.gc, False, False);
    XFillRectangle(XtDisplay(tf), XtWindow(tf), tf->text.gc, *x, 
		   y - TextF_FontAscent(tf), x_seg_len,
		   TextF_FontAscent(tf) + TextF_FontDescent(tf));
    SetInvGC(tf, tf->text.gc);
  } else {
    SetInvGC(tf, tf->text.gc);
    XFillRectangle(XtDisplay(tf), XtWindow(tf), tf->text.gc, *x, 
		   y - TextF_FontAscent(tf), x_seg_len,
		   TextF_FontAscent(tf) + TextF_FontDescent(tf));
    SetNormGC(tf, tf->text.gc, True, stipple);
  }
  
  if (tf->text.max_char_size != 1) {
    DrawText(tf, tf->text.gc, *x, y, (char*) (TextF_WcValue(tf) + seg_start),
	     (int)seg_end - (int)seg_start);
  } else {
    DrawText(tf, tf->text.gc, *x, y, TextF_Value(tf) + seg_start,
	     (int)seg_end - (int)seg_start);
  }
  if (stipple) SetNormGC(tf, tf->text.gc, True, !stipple);
  
  if (mode == XmHIGHLIGHT_SECONDARY_SELECTED)
    XDrawLine(XtDisplay(tf), XtWindow(tf), tf->text.gc, *x, y,
	      *x + x_seg_len - 1, y);
  
  /* update x position up to the next highlight position */
  if (tf->text.max_char_size != 1)
    *x += FindPixelLength(tf, (char*) (TextF_WcValue(tf) + seg_start),
			  (int)(next_seg - (int)seg_start));
  else
    *x += FindPixelLength(tf, TextF_Value(tf) + seg_start,
			  (int)(next_seg - (int)seg_start));
}


/*
 * Redisplay the new adjustments that have been made the the text
 * field widget.
 */
static void 
RedisplayText(XmTextFieldWidget tf,
	      XmTextPosition start,
	      XmTextPosition end)
{
  _XmHighlightRec *l = tf->text.highlight.list;
  XRectangle rect;
  int x, y, i;
  Dimension margin_width = TextF_MarginWidth(tf) +
    tf->primitive.shadow_thickness +
      tf->primitive.highlight_thickness;
  Dimension margin_top = tf->text.margin_top + tf->primitive.shadow_thickness +
    tf->primitive.highlight_thickness;
  Dimension margin_bottom = tf->text.margin_bottom +
    tf->primitive.shadow_thickness +
      tf->primitive.highlight_thickness;
  Boolean stipple = False;
  
  if (!XtIsRealized((Widget)tf)) return;
  
  if (tf->text.in_setvalues) {
    tf->text.redisplay = True;
    return;
  }
  
  if ((int)tf->core.width - (int)(2 * margin_width) <= 0)
    return;
  if ((int)tf->core.height - (int)(margin_top + margin_bottom) <= 0)
    return;
  
  _XmTextFieldDrawInsertionPoint(tf, False);
  
  /* Get the current rectangle.
   */
  GetRect(tf, &rect);
  
  x = (int) tf->text.h_offset;
  y = margin_top + TextF_FontAscent(tf);
  
  if (!XtIsSensitive((Widget)tf)) stipple = True;
  
  /* search through the highlight array and draw the text */
  for (i = 0; i + 1 < tf->text.highlight.number; i++) {
    
    /* make sure start is within current highlight */
    if (l[i].position <= start && start < l[i+1].position &&
	l[i].position < end) {
      
      if (end > l[i+1].position) {
	
	DrawTextSegment(tf, l[i].mode, l[i].position, start,
			l[i+1].position, l[i+1].position, stipple, y, &x);
	
	/* update start position to the next highlight position */
	start = l[i+1].position;
	
      } else {
	
 	if (start > end) {
	    XmTextPosition tmp = start;
	    start = end;
	    end = tmp;
 	}

	DrawTextSegment(tf, l[i].mode, l[i].position, start,
			end, l[i+1].position, stipple, y, &x);
	start = end;
      }
    } else { /* start not within current record */
      if (tf->text.max_char_size != 1)
	x += FindPixelLength(tf, (char*)(TextF_WcValue(tf) + l[i].position),
			     (int)(l[i+1].position - l[i].position));
      else
	x += FindPixelLength(tf, TextF_Value(tf) + l[i].position,
			     (int)(l[i+1].position - l[i].position));
    }
  }  /* end for loop */
  
  /* complete the drawing of the text to the end of the line */
  if (l[i].position < end) {
    DrawTextSegment(tf, l[i].mode, l[i].position, start,
		    end, tf->text.string_length, stipple, y, &x);
  } else {
    if (tf->text.max_char_size != 1)
      x += FindPixelLength(tf, (char*) (TextF_WcValue(tf) + l[i].position),
			   tf->text.string_length - (int)l[i].position);
    else 
      x += FindPixelLength(tf, TextF_Value(tf) + l[i].position,
			   tf->text.string_length - (int)l[i].position);
  }
  
  if (x < (Position)(rect.x + rect.width)) {
    SetInvGC(tf, tf->text.gc);
    XFillRectangle(XtDisplay(tf), XtWindow(tf), tf->text.gc, x, rect.y,
		   rect.x + rect.width - x, rect.height);
  }
  tf->text.refresh_ibeam_off = True;
  _XmTextFieldDrawInsertionPoint(tf, True);
}


/*
 * Use the font along with the resources that have been set
 * to determine the height and width of the text field widget.
 */
static void 
ComputeSize(XmTextFieldWidget tf,
	    Dimension *width,
	    Dimension *height)
{
  Dimension tmp = 0;
  
  if (TextF_ResizeWidth(tf) &&
      TextF_Columns(tf) < tf->text.string_length) {
    
    if (tf->text.max_char_size != 1) 
      tmp = FindPixelLength(tf, (char *)TextF_WcValue(tf),
			    tf->text.string_length);
    else
      tmp = FindPixelLength(tf, TextF_Value(tf), tf->text.string_length);
    
    
    *width = tmp + (2 * (TextF_MarginWidth(tf) + 
			 tf->primitive.shadow_thickness + 
			 tf->primitive.highlight_thickness));
  } else {
    *width = TextF_Columns(tf) * tf->text.average_char_width +
      2 * (TextF_MarginWidth(tf) + tf->primitive.shadow_thickness +
	   tf->primitive.highlight_thickness);
  }
  
  if (height != NULL)
    *height = TextF_FontDescent(tf) + TextF_FontAscent(tf) +
      2 * (TextF_MarginHeight(tf) + tf->primitive.shadow_thickness +
	   tf->primitive.highlight_thickness);
}


/*
 * TryResize - Attempts to resize the width of the text field widget.
 * If the attempt fails or is ineffective, return GeometryNo.
 */
static XtGeometryResult 
TryResize(XmTextFieldWidget tf,
#if NeedWidePrototypes
	  int width,
	  int height)
#else
          Dimension width,
          Dimension height)
#endif /* NeedWidePrototypes */
{
  Dimension reswidth, resheight;
  Dimension origwidth = tf->core.width;
  XtGeometryResult result;
  
  result = XtMakeResizeRequest((Widget)tf, width, height,
			       &reswidth, &resheight);
  
  if (result == XtGeometryAlmost) {
    result = XtMakeResizeRequest((Widget)tf, reswidth, resheight,
				 &reswidth, &resheight);
    
    if (reswidth == origwidth)
      result = XtGeometryNo;
    return result;
  }
  
  /*
   * Caution: Some geometry managers return XtGeometryYes
   *	        and don't change the widget's size.
   */
  if (tf->core.width != width || tf->core.height != height)
    result = XtGeometryNo;
  
  return result;
}


/*
 * Function AdjustText
 *
 * AdjustText ensures that the character at the given position is entirely
 * visible in the Text Field widget.  If the character is not already entirely
 * visible, AdjustText changes the Widget's h_offset appropriately.  If
 * the text must be redrawn, AdjustText calls RedisplayText.
 *
 */
static Boolean 
AdjustText(XmTextFieldWidget tf,
	   XmTextPosition position,
#if NeedWidePrototypes
	   int flag)
#else
           Boolean flag)
#endif /* NeedWidePrototypes */
{
  int left_edge = 0;
  int diff;
  Dimension margin_width = TextF_MarginWidth(tf) +
    tf->primitive.shadow_thickness +
      tf->primitive.highlight_thickness;
  Dimension thickness    = 2 * (tf->primitive.shadow_thickness +
				tf->primitive.highlight_thickness);
  Dimension temp;
  
  
  if (tf->text.max_char_size != 1) {
    left_edge = FindPixelLength(tf, (char *) TextF_WcValue(tf),
				(int)position) + (int) tf->text.h_offset;
  } else {
    left_edge = FindPixelLength(tf, TextF_Value(tf), (int)position) +
      (int) tf->text.h_offset;
  }
  
  if (left_edge <= (int)margin_width &&
      position == tf->text.string_length) {
    position = MAX(position - TextF_Columns(tf)/2, 0);
    if (tf->text.max_char_size != 1) {
      left_edge = FindPixelLength(tf, (char *) TextF_WcValue(tf),
				  (int)position) + (int) tf->text.h_offset;
    } else {
      left_edge = FindPixelLength(tf, TextF_Value(tf), (int)position) +
	(int) tf->text.h_offset;
    }
  }
      
  if ((diff = left_edge - margin_width) < 0) {
    /* We need to scroll the string to the right. */
    if (!XtIsRealized((Widget)tf)) {
      tf->text.h_offset -= diff;
      return True;
    }
    _XmTextFieldDrawInsertionPoint(tf, False);
    tf->text.h_offset -= diff;
    SetInvGC(tf, tf->text.gc);
    SetFullGC(tf, tf->text.gc);
    if (tf->core.height <= thickness)
      temp = 0;
    else
      temp = tf->core.height - thickness;
    XFillRectangle(XtDisplay(tf), XtWindow(tf), tf->text.gc,
		   tf->primitive.shadow_thickness +
		   tf->primitive.highlight_thickness,
		   tf->primitive.shadow_thickness +
		   tf->primitive.highlight_thickness,
		   TextF_MarginWidth(tf),
		   temp);
    SetMarginGC(tf, tf->text.gc);
    RedisplayText(tf, 0, tf->text.string_length); 
    _XmTextFieldDrawInsertionPoint(tf, True);
    return True;
  } else if ((diff = (left_edge -
		      (int)(tf->core.width - margin_width))) > 0) {
    /* We need to scroll the string to the left. */
    if (!XtIsRealized((Widget)tf)) {
      tf->text.h_offset -= diff;
      return True;
    }
    _XmTextFieldDrawInsertionPoint(tf, False);
    tf->text.h_offset -= diff;
    SetInvGC(tf, tf->text.gc);
    SetFullGC(tf, tf->text.gc);
    if (tf->core.width <= thickness)
      temp = 0;
    else
      temp = tf->core.width - thickness;
    XFillRectangle(XtDisplay(tf), XtWindow(tf), tf->text.gc,
		   tf->core.width - margin_width,
		   tf->primitive.shadow_thickness +
		   tf->primitive.highlight_thickness,
		   TextF_MarginWidth(tf),
		   temp);
    SetMarginGC(tf, tf->text.gc);
    RedisplayText(tf, 0, tf->text.string_length); 
    _XmTextFieldDrawInsertionPoint(tf, True);
    return True;
  }
  
  if (flag) RedisplayText(tf, position, tf->text.string_length); 
  
  return False;
}

/*
 * AdjustSize
 *
 * Adjust size will resize the text to ensure that all the text is visible.
 * It will also adjust text that is shrunk.  Shrinkage is limited to the
 * size determined by the XmNcolumns resource.
 */
static void 
AdjustSize(XmTextFieldWidget tf)
{
  XtGeometryResult result = XtGeometryYes;
  int left_edge = 0;
  int diff;
  Boolean redisplay = False;
  Dimension margin_width = TextF_MarginWidth(tf) +
    tf->primitive.shadow_thickness +
      tf->primitive.highlight_thickness;
  
  if (tf->text.max_char_size != 1) {
    left_edge = FindPixelLength(tf, (char *) TextF_WcValue(tf), 
				tf->text.string_length) + margin_width;
  } else {
    left_edge = FindPixelLength(tf, TextF_Value(tf), 
				tf->text.string_length) + margin_width;
  }
  
  if ((diff = (left_edge - (tf->core.width - (margin_width)))) > 0) {
    if (tf->text.in_setvalues) {
      tf->core.width += diff;
      return;
    }
    /* Attempt to resize.  If it doesn't succeed, do scrolling.  */
    result = TryResize(tf, tf->core.width + diff, tf->core.height);
    if (result == XtGeometryYes) {
      XtWidgetProc resize;

      _XmProcessLock();
      resize = tf->core.widget_class->core_class.resize;
      _XmProcessUnlock();
      (*resize)((Widget)tf);
      return;
    } else {
      /* We need to scroll the string to the left. */
      tf->text.h_offset = margin_width - diff;
    }
  } else {
    Dimension width;
    
    /* If the new size is smaller than core size, we need
     * to shrink.  Note: new size will never be less than the
     * width determined by the columns resource.
     */
    ComputeSize(tf, &width, NULL);
    if (width < tf->core.width) {
      if (tf->text.in_setvalues) {
	tf->core.width = width;
	return;
      }
      result = TryResize(tf, width, tf->core.height);
      if (result == XtGeometryYes) {
	XtWidgetProc resize;

	_XmProcessLock();
	resize = tf->core.widget_class->core_class.resize;
	_XmProcessUnlock();
	(*resize)((Widget)tf);

	return;
      }
    }
  }
  
  redisplay = AdjustText(tf, TextF_CursorPosition(tf), False);
  
  if (!redisplay)
    RedisplayText(tf, 0, tf->text.string_length);
}

/* If MB_CUR_MAX == 1, insert is a char* pointer; else, it is a wchar_t *
 * pointer and must be appropriately cast.  In all cases, insert_length
 * is the number of characters, not the number of bytes pointed to by
 * insert
 */
static Boolean 
ModifyVerify(XmTextFieldWidget tf,
	     XEvent *event,
	     XmTextPosition *replace_prev,
	     XmTextPosition *replace_next,
	     char **insert,
	     int *insert_length,
	     XmTextPosition *newInsert,
	     int *free_insert)
{
  XmTextVerifyCallbackStruct vcb;
  XmTextVerifyCallbackStructWcs wcs_vcb;
  XmTextBlockRec newblock;
  XmTextBlockRecWcs wcs_newblock;
  Boolean do_free = False;
  Boolean wcs_do_free = False;
  int count;
  wchar_t *wptr;
  
  *newInsert = TextF_CursorPosition(tf);
  *free_insert = (int)False;
  
  /* if there are no callbacks, don't waste any time... just return  True */
  if (!TextF_ModifyVerifyCallback(tf) && !TextF_ModifyVerifyCallbackWcs(tf))
    return(True);

  newblock.format = XmFMT_8_BIT;
  newblock.length = *insert_length * tf->text.max_char_size;
  
  if (*insert_length) {
    if (TextF_ModifyVerifyCallback(tf)) {
      newblock.ptr = (char *) XtMalloc((unsigned)newblock.length + 
				       tf->text.max_char_size);
      if (tf->text.max_char_size == 1) {
	(void)memcpy((void*)newblock.ptr, (void*)*insert,
		     newblock.length);
	newblock.ptr[newblock.length]='\0';
      } else {
	count = (int) wcstombs(newblock.ptr, (wchar_t*)*insert,
			       newblock.length);
	if (count < 0) { /* bad wchar; don't pass anything */
	  newblock.ptr[0] = '\0';
	  newblock.length = 0;
	} else if (count == newblock.length) {
	  newblock.ptr[newblock.length] = '\0';
	} else {
	  newblock.ptr[count] = '\0';
	  newblock.length = count;
	}
      }
      do_free = True;
    } else 
      newblock.ptr = NULL;
  } else 
    newblock.ptr = NULL;
  
  /* Fill in the appropriate structs */
  vcb.reason = XmCR_MODIFYING_TEXT_VALUE;
  vcb.event = (XEvent *) event;
  vcb.doit = True;
  vcb.currInsert = TextF_CursorPosition(tf);
  vcb.newInsert = TextF_CursorPosition(tf);
  vcb.text = &newblock;
  vcb.startPos = *replace_prev;
  vcb.endPos = *replace_next;
  
  /* Call the modify verify callbacks. */
  if (TextF_ModifyVerifyCallback(tf))
    XtCallCallbackList((Widget) tf, TextF_ModifyVerifyCallback(tf),
		       (XtPointer) &vcb);
  
  if (TextF_ModifyVerifyCallbackWcs(tf) && vcb.doit) {
    if (do_free) { /* there is a char* modify verify callback; the data we
		    * want is in vcb struct */
      wcs_newblock.wcsptr = (wchar_t *) XtMalloc((unsigned) 
						 (vcb.text->length + 1) * 
						 sizeof(wchar_t));
      wcs_newblock.length = mbstowcs(wcs_newblock.wcsptr, vcb.text->ptr,
				     vcb.text->length);
      if (wcs_newblock.length < 0) { /* bad value; don't pass anything */
	wcs_newblock.wcsptr[0] = 0L;
	wcs_newblock.length = 0;
      } else 
	wcs_newblock.wcsptr[wcs_newblock.length] = 0L;
    } else { /* there was no char* modify verify callback; use data
	      * passed in from caller instead of that in vcb struct. */
      wcs_newblock.wcsptr = (wchar_t *) XtMalloc((unsigned) 
						 (*insert_length + 1) * 
						 sizeof(wchar_t));
      if (tf->text.max_char_size == 1) 
	wcs_newblock.length = mbstowcs(wcs_newblock.wcsptr, *insert,
				       *insert_length);
      else {
	wcs_newblock.length = *insert_length;
	(void)memcpy((void*)wcs_newblock.wcsptr, (void*)*insert,
		     *insert_length * sizeof(wchar_t));
      }	    
      if (wcs_newblock.length < 0) { /* bad value; don't pass anything */
	wcs_newblock.wcsptr[0] = 0L;
	wcs_newblock.length = 0;
      } else 
	wcs_newblock.wcsptr[wcs_newblock.length] = 0L;
      
    }
    wcs_do_free = True;
    wcs_vcb.reason = XmCR_MODIFYING_TEXT_VALUE;
    wcs_vcb.event = (XEvent *) event;
    wcs_vcb.doit = True;
    wcs_vcb.currInsert = vcb.currInsert;
    wcs_vcb.newInsert = vcb.newInsert;
    wcs_vcb.text = &wcs_newblock;
    wcs_vcb.startPos = vcb.startPos;
    wcs_vcb.endPos = vcb.endPos;
    
    XtCallCallbackList((Widget) tf, TextF_ModifyVerifyCallbackWcs(tf),
		       (XtPointer) &wcs_vcb);
    
  }
  /* copy the newblock.ptr, length, start, and end to the pointers passed */
  if (TextF_ModifyVerifyCallbackWcs(tf)) { /* use wcs_vcb data */
    *insert_length = wcs_vcb.text->length; /* length is char count*/
    if (wcs_vcb.doit) {
      if (tf->text.max_char_size == 1) { /* caller expects char */
	wcs_vcb.text->wcsptr[wcs_vcb.text->length] = 0L;
	if (*insert_length > 0) {
	  *insert = XtMalloc((unsigned) *insert_length + 1);
	  *free_insert = (int)True;
	  count = wcstombs(*insert, wcs_vcb.text->wcsptr,
			   *insert_length + 1);
	  if (count < 0) {
	    (*insert)[0] = 0;
	    *insert_length = 0;
	  }
	}        
      } else {  /* callback struct has wchar*; caller expects wchar* */
	if (*insert_length > 0) {
	  *insert = 
	    XtMalloc((unsigned)(*insert_length + 1) * sizeof(wchar_t));
	  *free_insert = (int)True;
	  (void)memcpy((void*)*insert, (void*)wcs_vcb.text->wcsptr,
		       *insert_length * sizeof(wchar_t));
	  wptr = (wchar_t*) *insert;
	  wptr[*insert_length] = 0L;
	}
      }
      *replace_prev = wcs_vcb.startPos;
      *replace_next = wcs_vcb.endPos;
      *newInsert = wcs_vcb.newInsert;
    }
  } else { /* use vcb data */
    if (vcb.doit) {
      if (tf->text.max_char_size == 1) {  /* caller expects char* */
	*insert_length =  vcb.text->length;
	if (*insert_length > 0) {
	  *insert = XtMalloc((unsigned) *insert_length + 1);
	  *free_insert = (int)True;
	  (void)memcpy((void*)*insert, (void*)vcb.text->ptr,
		       *insert_length);
	  (*insert)[*insert_length] = 0;
	}
      } else {                       /* caller expects wchar_t* back */
	*insert_length =  _XmTextFieldCountCharacters(tf, vcb.text->ptr,
						      vcb.text->length);
	if (*insert_length > 0) {
	  *insert = 
	    XtMalloc((unsigned)(*insert_length + 1) * sizeof(wchar_t));
	  *free_insert = (int)True;
	  count = mbstowcs((wchar_t*)*insert, vcb.text->ptr,
			   *insert_length);
	  wptr = (wchar_t*) *insert;
	  if (count < 0) {
	    wptr[0] = 0L;
	    *insert_length = 0;
	  } else 
	    wptr[count] = 0L;
	}
      }
      *replace_prev = vcb.startPos;
      *replace_next = vcb.endPos;
      *newInsert = vcb.newInsert;
    }
  }
  if (do_free) XtFree(newblock.ptr);
  if (wcs_do_free) XtFree((char*)wcs_newblock.wcsptr);
  
  /* If doit becomes False, then don't allow the change. */
  if (TextF_ModifyVerifyCallbackWcs(tf))
    return wcs_vcb.doit;
  else
    return vcb.doit;
}

static void 
ResetClipOrigin(XmTextFieldWidget tf)
{
  int x, y;
  Position x_pos, y_pos;

  (void) GetXYFromPos(tf, TextF_CursorPosition(tf), &x_pos, &y_pos);
  
  if (!XtIsRealized((Widget)tf)) return;
  
  x = (int) x_pos; y = (int) y_pos;
  
  x -=(tf->text.cursor_width >> 1) + 1;
  
  y = (y + TextF_FontDescent(tf)) - tf->text.cursor_height;
  
  XSetTSOrigin(XtDisplay(tf), tf->text.image_gc, x, y);
}

static void
InvertImageGC (XmTextFieldWidget tf)
{
  if (tf->text.have_inverted_image_gc) return;
  
  tf->text.have_inverted_image_gc = True;
}

static void
ResetImageGC (XmTextFieldWidget tf)
{
  if (!tf->text.have_inverted_image_gc) return;
  
  tf->text.have_inverted_image_gc = False;
}



/*
 * Calls the motion verify callback.  If the doit flag is true,
 * then reset the cursor_position and call AdjustText() to
 * move the text if need be.
 */

void 
_XmTextFieldSetCursorPosition(XmTextFieldWidget tf,
			      XEvent *event,
			      XmTextPosition position,
#if NeedWidePrototypes
			      int adjust_flag,
			      int call_cb)
#else
                              Boolean adjust_flag,
                              Boolean call_cb)
#endif /* NeedWidePrototypes */
{
  SetCursorPosition(tf, event, position, adjust_flag, call_cb, True,DontCare);
}

static void 
SetCursorPosition(XmTextFieldWidget tf,
		  XEvent *event,
		  XmTextPosition position,
#if NeedWidePrototypes
		  int adjust_flag,
		  int call_cb, 
		  int set_dest,
#else
                  Boolean adjust_flag,
                  Boolean call_cb,
                  Boolean set_dest,
#endif /* NeedWidePrototypes */
		  PassDisown passDisown)
{
  XmTextVerifyCallbackStruct cb;
  Boolean flag = False;
  XPoint xmim_point;
  XRectangle xmim_area;
  _XmHighlightRec *hl_list = tf->text.highlight.list;
  int i;
  
  if (position < 0) position = 0;
  
  if (position > tf->text.string_length)
    position = tf->text.string_length;
  
  if (TextF_CursorPosition(tf) != position && call_cb) {
    /* Call Motion Verify Callback before Cursor Changes Positon */
    cb.reason = XmCR_MOVING_INSERT_CURSOR;
    cb.event  = event;
    cb.currInsert = TextF_CursorPosition(tf);
    cb.newInsert = position;
    cb.doit = True;
    XtCallCallbackList((Widget) tf, TextF_MotionVerifyCallback(tf),
		       (XtPointer) &cb);
    
    if (!cb.doit) {
      if (tf->text.verify_bell) XBell(XtDisplay((Widget)tf), 0);
      return;
    }
  }
  _XmTextFieldDrawInsertionPoint(tf, False);
  
  TextF_CursorPosition(tf) = position;
  
  if (!tf->text.add_mode && tf->text.pending_off && tf->text.has_primary) {
    SetSelection(tf, position, position, True);
    flag = True;
  }
  
  /* Deterimine if we need an inverted image GC or not.  Get the highlight
   * record for the cursor position.  If position is on a boundary of
   * a highlight, then we always display cursor in normal mode (i.e. set
   * normal image GC).  If position is within a selected highlight rec,
   * then make sure the image GC is inverted.  If we've moved out of a
   * selected highlight region, restore the normal image GC. */
  
  for (i = tf->text.highlight.number - 1; i >= 0; i--) {
    if (position >= hl_list[i].position || i == 0)
      break;
  }
  
  if (position == hl_list[i].position)
    ResetImageGC(tf);
  else if (hl_list[i].mode != XmHIGHLIGHT_SELECTED)
    ResetImageGC(tf);
  else 
    InvertImageGC(tf);
  
  if (adjust_flag) (void) AdjustText(tf, position, flag);
  
  tf->text.refresh_ibeam_off = True;
  _XmTextFieldDrawInsertionPoint(tf, True);
  
  (void) GetXYFromPos(tf, TextF_CursorPosition(tf),
		      &xmim_point.x, &xmim_point.y);
  (void)TextFieldGetDisplayRect((Widget)tf, &xmim_area);
  XmImVaSetValues((Widget)tf, XmNspotLocation, &xmim_point, 
		  XmNarea, &xmim_area, NULL);
  
  if (set_dest)
    (void) SetDestination((Widget) tf, TextF_CursorPosition(tf), 
		(DontCare == passDisown) ? False : True, 
			  XtLastTimestampProcessed(XtDisplay((Widget)tf)));
}


/*
 * This routine is used to verify that the positions are within the bounds
 * of the current TextField widgets value.  Also, it ensures that left is
 * less than right.
 */
static void 
VerifyBounds(XmTextFieldWidget tf,
	     XmTextPosition *from,
	     XmTextPosition *to)
{
  XmTextPosition tmp;
  
  if (*from < 0) 
    *from = 0;
  else if (*from > tf->text.string_length) {
    *from = tf->text.string_length;
  }
  if (*to < 0) 
    *to = 0;
  else if (*to > tf->text.string_length) {
    *to = tf->text.string_length;
  }
  if (*from > *to) {
    tmp = *to;
    *to = *from;
    *from = tmp;
  }
}

/*
 * Function _XmTextFieldReplaceText
 *
 * _XmTextFieldReplaceText is a utility function for the text-modifying
 * action procedures below (InsertChar, DeletePrevChar, and so on). 
 * _XmTextFieldReplaceText does the real work of editing the string,
 * including:
 *
 *   (1) invoking the modify verify callbacks,
 *   (2) allocating more memory for the string if necessary,
 *   (3) doing the string manipulation,
 *   (4) moving the selection (the insertion point), and
 *   (5) redrawing the text.
 *
 * Though the procedure claims to take a char* argument, MB_CUR_MAX determines
 * what the different routines will actually pass to it.  If MB_CUR_MAX is
 * greater than 1, then "insert" points to wchar_t data and we must set up
 * the appropriate cast.  In all cases, insert_length is the number of
 * characters (not bytes) to be inserted.
 */
Boolean 
_XmTextFieldReplaceText(XmTextFieldWidget tf,
			XEvent *event,
			XmTextPosition replace_prev,
			XmTextPosition replace_next,
			char *insert,
			int insert_length,
#if NeedWidePrototypes
			int move_cursor)
#else
                        Boolean move_cursor)
#endif /* NeedWidePrototypes */
{
  int replace_length, i;
  char *src, *dst;
  wchar_t *wc_src, *wc_dst;
  int delta = 0;
  XmTextPosition cursorPos, newInsert;
  XmTextPosition old_pos = replace_prev;
  int free_insert = (int)False;
  char *insert_orig;
  int insert_length_orig;
  
  VerifyBounds(tf, &replace_prev, &replace_next);
  
  if (!TextF_Editable(tf)) {
    if (tf->text.verify_bell) XBell(XtDisplay((Widget)tf), 0);
    return False;
  }

  if (tf->text.programmatic_highlights)
  {
  	/*
	** XmTextFieldSetHighlight called since last interaction here
	** that resulted in clearing program-set highlights
	*/
	int low,high;
	if (TrimHighlights(tf, &low, &high))
		{
	    	RedisplayText(tf, low, high);
		tf->text.programmatic_highlights = False;
		}
  }
  
  replace_length = (int) (replace_next - replace_prev);
  delta = insert_length - replace_length;
  
  /* Disallow insertions that go beyond max length boundries.
   */
  if ((delta >= 0) && !FUnderVerifyPreedit(tf) &&
      ((tf->text.string_length + delta) - (TextF_MaxLength(tf)) > 0)) { 
    if (tf->text.verify_bell) XBell(XtDisplay(tf), 0);
    return False;
  }
  
  
  /* If there are modify verify callbacks, verify that we want to continue
   * the action.
   */
  newInsert = TextF_CursorPosition(tf);
  
  if (TextF_ModifyVerifyCallback(tf) || TextF_ModifyVerifyCallbackWcs(tf)) {
    /* If the function ModifyVerify() returns false then don't
     * continue with the action.
     */
    insert_length_orig = insert_length;
    if (insert_length > 0) {
    	insert_orig = XtMalloc(insert_length * tf->text.max_char_size);
    	bcopy(insert, insert_orig, insert_length * tf->text.max_char_size);
    } else
	insert_orig = NULL;
    if (!ModifyVerify(tf, event, &replace_prev, &replace_next,
		      &insert, &insert_length, &newInsert, &free_insert)) {
      if (tf->text.verify_bell) XBell(XtDisplay(tf), 0);
      if (free_insert) XtFree(insert);
      if (FUnderVerifyPreedit(tf)) {
	FVerifyCommitNeeded(tf) = True;
	PreEnd(tf) -= insert_length_orig;
      }
      return False;
    } else {
      if (FUnderVerifyPreedit(tf))
	if (insert_length != insert_length_orig ||
          memcmp(insert, insert_orig, 
		  insert_length * tf->text.max_char_size) != 0) {
	  FVerifyCommitNeeded(tf) = True;
	  PreEnd(tf) += insert_length - insert_length_orig;
	}
	  
      VerifyBounds(tf, &replace_prev, &replace_next);
      replace_length = (int) (replace_next - replace_prev);
      delta = insert_length - replace_length;
      
      /* Disallow insertions that go beyond max length boundries.
       */
      if ((delta >= 0) && !FUnderVerifyPreedit(tf) &&
	  ((tf->text.string_length + delta) - (TextF_MaxLength(tf)) > 0)) { 
	if (tf->text.verify_bell) XBell(XtDisplay(tf), 0);
	if (free_insert) XtFree(insert);
	return False;
      }
      
    }
    XtFree(insert_orig);
  }
  
  /* make sure selections are turned off prior to changeing text */
  if (tf->text.has_primary &&
      tf->text.prim_pos_left != tf->text.prim_pos_right)
    doSetHighlight((Widget)tf, tf->text.prim_pos_left,
			    tf->text.prim_pos_right, XmHIGHLIGHT_NORMAL);
  
  _XmTextFieldDrawInsertionPoint(tf, False);
  
  /* Allocate more space if we need it.
   */
  if (tf->text.max_char_size == 1) {
    if (tf->text.string_length + insert_length - replace_length >=
	tf->text.size_allocd) {
      tf->text.size_allocd += MAX(insert_length + TEXT_INCREMENT,
				  (tf->text.size_allocd * 2));
      tf->text.value = 
	(char *) XtRealloc((char*)TextF_Value(tf), 
			   (unsigned) (tf->text.size_allocd * sizeof(char)));
    }
  } else {
    if ((tf->text.string_length + insert_length - replace_length) *
	sizeof(wchar_t) >= tf->text.size_allocd) {
      tf->text.size_allocd +=
	MAX((insert_length + TEXT_INCREMENT)*sizeof(wchar_t),
	    (tf->text.size_allocd * 2));
      tf->text.wc_value = 
	(wchar_t *) XtRealloc((char*)TextF_WcValue(tf), 
			      (unsigned) tf->text.size_allocd);
    }
  }
  
  if (tf->text.has_primary && replace_prev < tf->text.prim_pos_right &&
      replace_next > tf->text.prim_pos_left) {
    if (replace_prev <= tf->text.prim_pos_left) {
      if (replace_next < tf->text.prim_pos_right) {
	/* delete encompasses left half of the selection
	 * so move left endpoint
	 */
	tf->text.prim_pos_left = replace_next;
      } else {
	/* delete encompasses the selection so set selection to NULL */
           tf->text.prim_pos_left = tf->text.prim_pos_right;
        }
       } else {
        /*
         * the 2 cases below were incorrect, and have now
         * been synchronized with the corresponding block of code in
         * TextStrSo.c
         */
        if (replace_next > tf->text.prim_pos_right) {
          /* delete encompasses the right half of the selection
           * so move right endpoint
           */
           tf->text.prim_pos_right = replace_prev;
        } else {
          /* delete is completely within the selection
           * so decrease size of selection.
           */
           tf->text.prim_pos_right -= (replace_next - replace_prev);
        }

       }
    }
  
  if (tf->text.max_char_size == 1) {
    if (replace_length > insert_length)
      /* We need to shift the text at and after replace_next to the left. */
      for (src = TextF_Value(tf) + replace_next,
	   dst = src + (insert_length - replace_length),
	   i = (int) ((tf->text.string_length + 1) - replace_next);
	   i > 0;
	   ++src, ++dst, --i)
	*dst = *src;
    else if (replace_length < insert_length)
      /* We need to shift the text at and after replace_next to the right. */
      /* Need to add 1 to string_length to handle the NULL terminator on */
      /* the string. */
      for (src = TextF_Value(tf) + tf->text.string_length,
	   dst = src + (insert_length - replace_length),
	   i = (int) ((tf->text.string_length + 1) - replace_next);
	   i > 0;
	   --src, --dst, --i)
	*dst = *src;
    
    /* Update the string.
     */
    if (insert_length != 0) {
      for (src = insert,
	   dst = TextF_Value(tf) + replace_prev,
	   i = insert_length;
	   i > 0;
	   ++src, ++dst, --i)
	*dst = *src;
    }
  } else {  /* have wchar_t* data */
    if (replace_length > insert_length)
      /* We need to shift the text at and after replace_next to the left. */
      for (wc_src = TextF_WcValue(tf) + replace_next,
	   wc_dst = wc_src + (insert_length - replace_length),
	   i = (int) ((tf->text.string_length + 1) - replace_next);
	   i > 0;
	   ++wc_src, ++wc_dst, --i)
	*wc_dst = *wc_src;
    else if (replace_length < insert_length)
      /* We need to shift the text at and after replace_next to the right. */
      /* Need to add 1 to string_length to handle the NULL terminator on */
      /* the string. */
      for (wc_src = TextF_WcValue(tf) + tf->text.string_length,
	   wc_dst = wc_src + (insert_length - replace_length),
	   i = (int) ((tf->text.string_length + 1) - replace_next);
	   i > 0;
	   --wc_src, --wc_dst, --i)
	*wc_dst = *wc_src;
    
    /* Update the string.
     */
    if (insert_length != 0) {
      for (wc_src = (wchar_t *)insert,
	   wc_dst = TextF_WcValue(tf) + replace_prev,
	   i = insert_length;
	   i > 0;
	   ++wc_src, ++wc_dst, --i)
	*wc_dst = *wc_src;
    }
  }
  
  if (tf->text.has_primary &&
      tf->text.prim_pos_left != tf->text.prim_pos_right) {
    if (replace_prev <= tf->text.prim_pos_left) {
      tf->text.prim_pos_left += delta;
      tf->text.prim_pos_right += delta;
    }
    if (tf->text.prim_pos_left > tf->text.prim_pos_right)
      tf->text.prim_pos_right = tf->text.prim_pos_left;
  }
  
  /* make sure the selection are redisplay, 
     since they were turned off earlier */
  if (tf->text.has_primary &&
      tf->text.prim_pos_left != tf->text.prim_pos_right)
    doSetHighlight((Widget)tf, tf->text.prim_pos_left,
			    tf->text.prim_pos_right, XmHIGHLIGHT_SELECTED);
  
  tf->text.string_length += insert_length - replace_length;
  
  if (move_cursor) {
    if (TextF_CursorPosition(tf) != newInsert) {
      if (newInsert > tf->text.string_length) {
	cursorPos = tf->text.string_length;
      } else if (newInsert < 0) {
	cursorPos = 0;
      } else {
	cursorPos = newInsert;
      }
    } else
      cursorPos = replace_next + (insert_length - replace_length);
    if (event != NULL) {
      (void)SetDestination((Widget)tf, cursorPos, False, event->xkey.time);
    } else {
      (void) SetDestination((Widget)tf, cursorPos, False,
			    XtLastTimestampProcessed(XtDisplay((Widget)tf)));
    }
    _XmTextFieldSetCursorPosition(tf, event, cursorPos, False, True);
  }
  
  if (TextF_ResizeWidth(tf) && tf->text.do_resize) {
    AdjustSize(tf);
  } else {
    AdjustText(tf, TextF_CursorPosition(tf), False);
    RedisplayText(tf, old_pos, tf->text.string_length);
  }
  
  _XmTextFieldDrawInsertionPoint(tf, True);
  if (free_insert) XtFree(insert);
  return True;
}


/*
 * Reset selection flag and selection positions and then display
 * the new settings.
 */
void 
_XmTextFieldDeselectSelection(Widget w,
#if NeedWidePrototypes
			      int disown,
#else
			      Boolean disown,
#endif /* NeedWidePrototypes */
			      Time sel_time)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  
  if (w != NULL && disown) {
    if (!sel_time) sel_time = _XmValidTimestamp(w);
    /*
     * Disown the primary selection (This function is a no-op if
     * this widget doesn't own the primary selection)
     */
    XtDisownSelection(w, XA_PRIMARY, sel_time);
  }
  if (tf != NULL) {
    _XmTextFieldDrawInsertionPoint(tf, False);
    tf->text.has_primary = False;
    tf->text.take_primary = True;
    TextFieldSetHighlight(tf, tf->text.prim_pos_left,
			  tf->text.prim_pos_right, XmHIGHLIGHT_NORMAL);
    tf->text.prim_pos_left = tf->text.prim_pos_right =
      tf->text.prim_anchor = TextF_CursorPosition(tf);
    
    if (!tf->text.has_focus && tf->text.add_mode) 
      tf->text.add_mode = False;
    
    RedisplayText(tf, 0, tf->text.string_length);
    
    _XmTextFieldDrawInsertionPoint(tf, True);
  }
}

/*
 * Finds the cursor position from the given X value.
 */
static XmTextPosition 
GetPosFromX(XmTextFieldWidget tf,
#if NeedWidePrototypes
	    int x)
#else
            Position x)
#endif /* NeedWidePrototypes */
{
  XmTextPosition position;
  int temp_x = 0;
  int next_char_width = 0;
  
  /* Decompose the x to equal the length of the text string */
  temp_x += (int) tf->text.h_offset;
  
  /* Next width is an offset allowing button presses on the left side 
   * of a character to select that character, while button presses
   * on the rigth side of the character select the  NEXT character.
   */
  
  if (tf->text.string_length > 0) {
    
    if (tf->text.max_char_size != 1) {
      next_char_width = FindPixelLength(tf, (char*)TextF_WcValue(tf), 1);
    } else {
      next_char_width = FindPixelLength(tf, TextF_Value(tf), 1);
    }
  }
  
  for (position = 0; temp_x + next_char_width/2 < (int) x &&
       position < tf->text.string_length; position++) {
    
    temp_x+=next_char_width;    /* 
				 * We still haven't reached the x pos.
				 * Add the width and find the next chars
				 * width. 
				 */
    
    /*
     * If there is a next position, find its width.  Otherwise, use the
     * current "next" width.
     */
    
    if (tf->text.string_length > position + 1) {
      if (tf->text.max_char_size != 1) {
	next_char_width = 
	  FindPixelLength(tf, (char*)(TextF_WcValue(tf) + position + 1), 1);
      } else {
	next_char_width = FindPixelLength(tf,
					  TextF_Value(tf) + position + 1, 1);
      }
    } 
  } /* for */
  
  return position;
}


/* ARGSUSED */
static Boolean 
SetDestination(Widget w,
	       XmTextPosition position,
#if NeedWidePrototypes
	       int disown,
#else
	       Boolean disown,
#endif /* NeedWidePrototypes */
	       Time set_time)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  Boolean result = TRUE;
  Atom MOTIF_DESTINATION = XInternAtom(XtDisplay(w),
				       XmS_MOTIF_DESTINATION, False);
  
  if (!XtIsRealized(w)) return False;
  
  _XmTextFieldDrawInsertionPoint(tf, False);
  
  if (!disown) {
    if (!tf->text.has_destination) {
      if (!set_time) set_time = _XmValidTimestamp(w);
      result = XmeSecondarySink(w, set_time);
      tf->text.dest_time = set_time;
      tf->text.has_destination = result;
      
      if (result) _XmSetDestination(XtDisplay(w), w);
    }
  } else {
    if (tf->text.has_destination) {
      if (!set_time) set_time = _XmValidTimestamp(w);
      XtDisownSelection(w, MOTIF_DESTINATION, set_time);

      /* Call XmGetDestination(dpy) to get widget that last had
	 destination cursor. */
      if (w == XmGetDestination(XtDisplay(w)))
	_XmSetDestination(XtDisplay(w), (Widget)NULL);
      
      tf->text.has_destination = False;
    }
  }
  
  _XmTextFieldDrawInsertionPoint(tf, True);
  
  return result;
}

Boolean 
_XmTextFieldSetDestination(Widget w,
			   XmTextPosition position,
			   Time set_time)
{
  Boolean result;
  
  result = SetDestination(w, position, False, set_time);
  
  return result;
}


/*
 * Calls the losing focus verify callback to verify that the application
 * want to traverse out of the text field widget.  Returns the result.
 */
static Boolean 
VerifyLeave(XmTextFieldWidget tf,
	    XEvent *event)
{
  XmTextVerifyCallbackStruct  cbdata;
  
  cbdata.reason = XmCR_LOSING_FOCUS;
  cbdata.event = event;
  cbdata.doit = True;
  cbdata.currInsert = TextF_CursorPosition(tf);
  cbdata.newInsert = TextF_CursorPosition(tf);
  cbdata.startPos = TextF_CursorPosition(tf);
  cbdata.endPos = TextF_CursorPosition(tf);
  cbdata.text = NULL;
  XtCallCallbackList((Widget) tf, TextF_LosingFocusCallback(tf), 
		     (XtPointer) &cbdata);
  tf->text.take_primary = True;
  return(cbdata.doit);
}

/* This routine is used to determine if two adjacent wchar_t characters
 * constitute a word boundary */
/* ARGSUSED */
static Boolean
_XmTextFieldIsWordBoundary(XmTextFieldWidget tf,
			   XmTextPosition pos1 ,
			   XmTextPosition pos2)
{
  int size_pos1 = 0;
  int size_pos2 = 0;
  char s1[MB_LEN_MAX];
  char s2[MB_LEN_MAX];
  
  /* if positions aren't adjacent, return False */
  if(pos1 < pos2 && ((pos2 - pos1) != 1)) 
    return False;
  else if(pos2 < pos1 && ((pos1 - pos2) != 1)) 
    return False;
  
  if (tf->text.max_char_size == 1) { /* data is char* and one-byte per char */
    if (isspace((unsigned char)TextF_Value(tf)[pos1]) || 
	isspace((unsigned char)TextF_Value(tf)[pos2])) return True;
  } else {
    size_pos1 = wctomb(s1, TextF_WcValue(tf)[pos1]);
    size_pos2 = wctomb(s2, TextF_WcValue(tf)[pos2]);
    if (size_pos1 == 1 && (size_pos2 != 1 || isspace((unsigned char)*s1)))
      return True;
    if (size_pos2 == 1 && (size_pos1 != 1 || isspace((unsigned char)*s2)))
      return True;
  }
  return False;
}

/* This routine accepts an array of wchar_t's containing wchar encodings
 * of whitespace characters (and the number of array elements), comparing
 * the wide character passed to each element of the array.  If a match
 * is found, we got a white space.  This routine exists only because
 * iswspace(3c) is not yet standard.  If a system has isw* available,
 * calls to this routine should be changed to iswspace(3c) (and callers
 * should delete initialization of the array), and this routine should
 * be deleted.  Its a stop gap measure to avoid allocating an instance
 * variable for the white_space array and/or declaring a widget wide
 * global for the data and using a macro.  Its ugly, but it works and 
 * in the long run will be replaced by standard functionality. */

/* ARGSUSED */
static Boolean
_XmTextFieldIsWSpace(wchar_t wide_char,
		     wchar_t * white_space ,
		     int num_entries)
{
  int i;
  
  for (i=0; i < num_entries; i++) {
    if (wide_char == white_space[i]) return True;
  }
  return False;
}

static void 
FindWord(XmTextFieldWidget tf,
	 XmTextPosition begin,
	 XmTextPosition *left,
	 XmTextPosition *right)
{
  XmTextPosition start, end;
  wchar_t white_space[3];
  
  if (tf->text.max_char_size == 1) {
    for (start = begin; start > 0; start--) {
      if (isspace((unsigned char)TextF_Value(tf)[start - 1])) {
	break;
      }
    }
    *left = start;
    
    for (end = begin; end <= tf->text.string_length; end++) {
      if (isspace((unsigned char)TextF_Value(tf)[end])) {
	end++;
	break;
      }
    }
    *right = end - 1;
  } else { /* check for iswspace and iswordboundary in each direction */
    (void)mbtowc(&white_space[0], " ", 1);
    (void)mbtowc(&white_space[1], "\n", 1);
    (void)mbtowc(&white_space[2], "\t", 1);
    for (start = begin; start > 0; start --) {
      if (_XmTextFieldIsWSpace(TextF_WcValue(tf)[start-1],white_space, 3)
	  || _XmTextFieldIsWordBoundary(tf, (XmTextPosition) start - 1, 
					start)) {
	break;
      }
    }
    *left = start;
    
    for (end = begin; end <= tf->text.string_length; end++) {
      if (_XmTextFieldIsWSpace(TextF_WcValue(tf)[end], white_space, 3)) {
	end++;
	break;
      } else if (end < tf->text.string_length) {
	if (_XmTextFieldIsWordBoundary(tf, end, (XmTextPosition)end + 1)) {
	  end += 2; /* want to return position of next word; end + 1 */
	  break;    /* is that position && *right = end - 1... */
	}
      }
    }
    *right = end - 1;
  }
}

static void 
FindPrevWord(XmTextFieldWidget tf,
	     XmTextPosition *left,
	     XmTextPosition *right)
{
  
  XmTextPosition start = TextF_CursorPosition(tf);
  wchar_t white_space[3];
  
  if (tf->text.max_char_size != 1) {
    (void)mbtowc(&white_space[0], " ", 1);
    (void)mbtowc(&white_space[1], "\n", 1);
    (void)mbtowc(&white_space[2], "\t", 1);
  }
  
  
  if (tf->text.max_char_size == 1) {
    if ((start > 0) && 
	(isspace((unsigned char)TextF_Value(tf)[start - 1]))) {
      for (; start > 0; start--) {
	if (!isspace((unsigned char)TextF_Value(tf)[start - 1])) {
	  start--;
	  break;
	}
      }
    }
    FindWord(tf, start, left, right);
  } else { 
    if ((start > 0) && (_XmTextFieldIsWSpace(TextF_WcValue(tf)[start - 1],
					     white_space, 3))) {
      for (; start > 0; start--) {
	if (!_XmTextFieldIsWSpace(TextF_WcValue(tf)[start -1], 
				  white_space, 3)) {
	  start--;
	  break;
	}
      }
    } else if ((start > 0) && 
	       _XmTextFieldIsWordBoundary(tf, (XmTextPosition) start - 1, 
					  start)) {
      start--;
    }
    FindWord(tf, start, left, right);
  }
}

static void 
FindNextWord(XmTextFieldWidget tf,
	     XmTextPosition *left,
	     XmTextPosition *right)
{
  
  XmTextPosition end = TextF_CursorPosition(tf);
  wchar_t white_space[3];
  
  if (tf->text.max_char_size != 1) {
    (void)mbtowc(&white_space[0], " ", 1);
    (void)mbtowc(&white_space[1], "\n", 1);
    (void)mbtowc(&white_space[2], "\t", 1);
  }
  
  
  if(tf->text.max_char_size == 1) {
    if (isspace((unsigned char)TextF_Value(tf)[end])) {
      for (end = TextF_CursorPosition(tf);
	   end < tf->text.string_length; end++) {
	if (!isspace((unsigned char)TextF_Value(tf)[end])) {
	  break;
	}
      }
    }
    FindWord(tf, end, left, right);
    /*
     * Set right to the last whitespace following the end of the
     * current word.
     */
    while (*right < tf->text.string_length &&
	   isspace((unsigned char)TextF_Value(tf)[(int)*right]))
      *right = *right + 1;
    if (*right < tf->text.string_length)
      *right = *right - 1;
  } else {
    if (_XmTextFieldIsWSpace(TextF_WcValue(tf)[end], white_space, 3)) {
      for (; end < tf->text.string_length; end ++) {
	if (!_XmTextFieldIsWSpace(TextF_WcValue(tf)[end], white_space, 3)) {
	  break;
	}
      }
    } else { /* if for other reasons at word boundry, advance to next word */
      if ((end < tf->text.string_length) && 
	  _XmTextFieldIsWordBoundary(tf, end, (XmTextPosition) end + 1))
	end++;
    }
    FindWord(tf, end, left, right);
    /*
     * If word boundary caused by whitespace, set right to the last 
     * whitespace following the end of the current word.
     */
    if (_XmTextFieldIsWSpace(TextF_WcValue(tf)[(int)*right], white_space, 3)) {
      while (*right < tf->text.string_length &&
	     _XmTextFieldIsWSpace(TextF_WcValue(tf)[(int)*right], 
				  white_space, 3)) {
	*right = *right + 1;
      }
      if (*right < tf->text.string_length)
	*right = *right - 1;
    }
  }
}

static void 
CheckDisjointSelection(Widget w,
		       XmTextPosition position,
		       Time sel_time)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  XmTextPosition left = tf->text.prim_pos_left, right = tf->text.prim_pos_right;
  
  if (tf->text.add_mode || 
      (tf->text.has_primary && left != right &&
       position >= left && position <= right))
    tf->text.pending_off = FALSE;
  else
    tf->text.pending_off = TRUE;
  
  if (left == right) {
    (void) SetDestination(w, position, False, sel_time);
    tf->text.prim_anchor = position;
  } else {
    (void) SetDestination(w, position, False, sel_time);
    if (!tf->text.add_mode) tf->text.prim_anchor = position;
  }
}

static Boolean 
NeedsPendingDelete(XmTextFieldWidget tf)
{
  return (tf->text.add_mode ?
	  (TextF_PendingDelete(tf) &&
	   tf->text.has_primary &&
	   tf->text.prim_pos_left != tf->text.prim_pos_right &&
	   tf->text.prim_pos_left <= TextF_CursorPosition(tf) &&
	   tf->text.prim_pos_right >= TextF_CursorPosition(tf)) :
	  (tf->text.has_primary &&
	   tf->text.prim_pos_left != tf->text.prim_pos_right));
}

static Boolean 
NeedsPendingDeleteDisjoint(XmTextFieldWidget tf)
{
  return (TextF_PendingDelete(tf) &&
	  tf->text.has_primary &&
	  tf->text.prim_pos_left != tf->text.prim_pos_right &&
	  tf->text.prim_pos_left <= TextF_CursorPosition(tf) &&
	  tf->text.prim_pos_right >= TextF_CursorPosition(tf));
}


/*ARGSUSED*/
static Boolean 
PrintableString(XmTextFieldWidget tf,
		char* str, 
		int n, 
		Boolean use_wchar) /* sometimes unused */
{
#ifdef SUPPORT_ZERO_WIDTH
  /* some locales (such as Thai) have characters that are
   * printable but non-spacing. These should be inserted,
   * even if they have zero width.
   */
  if (tf->text.max_char_size == 1) {
    int i;
    if (!use_wchar) {
      for (i = 0; i < n; i++) {
	if (!isprint((unsigned char)str[i])) {
	  return False;
	}
      }
    } else {
      char scratch[8];
      wchar_t *ws = (wchar_t *) str;
      for (i = 0; i < n; i++) {
	if (wctomb(scratch, ws[i]) <= 0)
	  return False;
	if (!isprint((unsigned char)scratch[0])) {
	  return False;
	}
      }
    }
    return True;
  } else {
    /* tf->text.max_char_size > 1 */
#ifdef HAS_WIDECHAR_FUNCTIONS
    if (use_wchar) {
      int i;
      wchar_t *ws = (wchar_t *) str;
      for (i = 0; i < n; i++) {
	if (!iswprint(ws[i])) {
	  return False;
	}
      }
      return True;
    } else {
      int i, csize;
      wchar_t wc;
#ifndef NO_MULTIBYTE
      for (i = 0, csize = mblen(str, tf->text.max_char_size);
	   i < n;
	   i += csize, csize=mblen(&(str[i]), tf->text.max_char_size))
#else
      for (i = 0, csize = *str ? 1 : 0; i < n;
	   i += csize, csize = str[i] ? 1 : 0)
#endif
	{
	  if (csize < 0) 
	    return False;
	  if (mbtowc(&wc, &(str[i]), tf->text.max_char_size) <= 0)
	    return False;
	  if (!iswprint(wc)) {
	    return False;
	  }
	}
    }
#else /* HAS_WIDECHAR_FUNCTIONS */ 
    /*
     * This will only check if any single-byte characters are non-
     * printable. Better than nothing...
     */
    int i, csize;
    if (!use_wchar) {
#ifndef NO_MULTIBYTE
      for (i = 0, csize = mblen(str, tf->text.max_char_size);
	   i < n;
	   i += csize, csize=mblen(&(str[i]), tf->text.max_char_size))
#else
      for (i = 0, csize = *str ? 1 : 0; i < n;
	   i += csize, csize = str[i] ? 1 : 0)
#endif
	{
	  if (csize < 0)
	    return False;
	  if (csize == 1 && !isprint((unsigned char)str[i])) {
	    return False;
	  }
	}
    } else {
      char scratch[8];
      wchar_t *ws = (wchar_t *) str;
      for (i = 0; i < n; i++) {
	if ((csize = wctomb(scratch, ws[i])) <= 0)
	  return False;
	if (csize == 1 && !isprint((unsigned char)scratch[0])) {
	  return False;
	}
      }
    }
#endif /* HAS_WIDECHAR_FUNCTIONS */
    return True;
  }
#else /* SUPPORT_ZERO_WIDTH */
  if (TextF_UseFontSet(tf)) {
      if(use_wchar) 
	  return (XwcTextEscapement((XFontSet)TextF_Font(tf), (wchar_t *)str, n) != 0);
      else
	  return (XmbTextEscapement((XFontSet)TextF_Font(tf), str, n) != 0);
  }
  else {
    if (use_wchar) {
      char cache[100];
      char *tmp, *cache_ptr; 
      wchar_t *tmp_str;
      int ret_val, buf_size, count;
      Boolean is_printable;
      buf_size = (n * MB_CUR_MAX) + 1;
      cache_ptr = tmp = XmStackAlloc(buf_size, cache);
   
      tmp_str = (wchar_t *)str;
      ret_val = wctomb(tmp, *tmp_str);
      count = 0;
      while ( (ret_val > 0)&& (buf_size >= MB_CUR_MAX) && (count < n) )
	{
	  count += 1;
	  tmp += ret_val;
	  buf_size -= ret_val;
	  tmp_str++;
	  ret_val = wctomb(tmp, *tmp_str);
	}
         
      if (ret_val == -1)    /* bad character */
	return (False);
 
      is_printable = XTextWidth(TextF_Font(tf), cache_ptr, tmp - cache_ptr);
      XmStackFree(cache_ptr, cache);
      return (is_printable);
    }
    else {
      return (XTextWidth(TextF_Font(tf), str, n) != 0);
    }
  }
#endif /* SUPPORT_ZERO_WIDTH */ 
}

/****************************************************************
 *
 * Input functions defined in the action table.
 *
 ****************************************************************/

/* ARGSUSED */
static void 
InsertChar(Widget w,
	   XEvent *event,
	   char **params,
	   Cardinal *num_params)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  char insert_string[TEXT_MAX_INSERT_SIZE + 1]; /* NULL-terminated below */
  XmTextPosition cursorPos, nextPos;
  wchar_t * wc_insert_string;
  int insert_length, i;
  int num_chars;
  Boolean replace_res;
  Boolean pending_delete = False;
  Status status_return;
  XmAnyCallbackStruct cb;
  
  /* Determine what was pressed.
   */
  insert_length = XmImMbLookupString(w, (XKeyEvent *) event, insert_string, 
		                     TEXT_MAX_INSERT_SIZE, (KeySym *) NULL, 
				     &status_return);
  
  if (insert_length > 0 && !TextF_Editable(tf)) {
    if (tf->text.verify_bell) XBell(XtDisplay((Widget)tf), 0);
    return;
  }
  
  /* If there is more data than we can handle, bail out */
  if (status_return == XBufferOverflow || insert_length > TEXT_MAX_INSERT_SIZE)
    return;
  
  /* *LookupString in some cases can return the NULL as a character, such
   * as when the user types <Ctrl><back_quote> or <Ctrl><@>.  Text widget
   * can't handle the NULL as a character, so we dump it here.
   */
  
  for (i=0; i < insert_length; i++)
    if (insert_string[i] == 0) insert_length = 0; /* toss out input string */

  if (insert_length > 0) {
    /* do not insert non-printing characters */
    if (!PrintableString(tf, insert_string, insert_length, False))
      return;
    
    _XmTextFieldDrawInsertionPoint(tf, False);
    if (NeedsPendingDeleteDisjoint(tf)) {
      if (!tf->text.has_primary || 
	  (cursorPos = tf->text.prim_pos_left) == 
	  (nextPos = tf->text.prim_pos_right)) {
	tf->text.prim_anchor = TextF_CursorPosition(tf);
      }
      pending_delete = True;
      
      tf->text.prim_anchor = TextF_CursorPosition(tf);
      
    } else {
      cursorPos = nextPos = TextF_CursorPosition(tf);
    }
    
    
    if (tf->text.max_char_size == 1) {
      if (tf->text.overstrike) nextPos += insert_length;
      if (nextPos > tf->text.string_length) nextPos = tf->text.string_length;
      replace_res = _XmTextFieldReplaceText(tf, (XEvent *) event, cursorPos,
					    nextPos, insert_string,
					    insert_length, True);
    } else {
      char stack_cache[100];
      insert_string[insert_length] = '\0'; /* NULL terminate for mbstowcs */
      wc_insert_string = (wchar_t*)XmStackAlloc((Cardinal)(insert_length+1) *
						sizeof(wchar_t), stack_cache);
      num_chars = mbstowcs(wc_insert_string, insert_string, insert_length+1);
      if (num_chars < 0) num_chars = 0;
      if (tf->text.overstrike) nextPos += num_chars;
      if (nextPos > tf->text.string_length) nextPos = tf->text.string_length;
      replace_res = _XmTextFieldReplaceText(tf, (XEvent *) event, cursorPos,
					    nextPos, (char*) wc_insert_string,
					    num_chars, True);
      XmStackFree((char *)wc_insert_string, stack_cache);
    }
    
    if (replace_res) {
      if (pending_delete) {
	_XmTextFieldStartSelection(tf, TextF_CursorPosition(tf),
				   TextF_CursorPosition(tf), event->xkey.time);
	tf->text.pending_off = False;
      }
      CheckDisjointSelection(w, TextF_CursorPosition(tf),
			     event->xkey.time);
      _XmTextFieldSetCursorPosition(tf, event, TextF_CursorPosition(tf), 
				    False, True);
      cb.reason = XmCR_VALUE_CHANGED;
      cb.event = event;
      XtCallCallbackList((Widget) tf, TextF_ValueChangedCallback(tf),
			 (XtPointer) &cb);
    }
    _XmTextFieldDrawInsertionPoint(tf, True);
  }
}

/* ARGSUSED */
static void 
DeletePrevChar(Widget w,
	       XEvent *event,
	       char **params,
	       Cardinal *num_params)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  XmAnyCallbackStruct cb;

  /* if pending delete is on and there is a selection */
  _XmTextFieldDrawInsertionPoint(tf, False);
  if (NeedsPendingDelete(tf)) (void) TextFieldRemove(w, event);
  else { 
    if (tf->text.has_primary &&
	tf->text.prim_pos_left != tf->text.prim_pos_right) {
      if (TextF_CursorPosition(tf) - 1 >= 0)
	if (_XmTextFieldReplaceText(tf, event, TextF_CursorPosition(tf) - 1,
				    TextF_CursorPosition(tf), NULL, 0, True)) {
	  CheckDisjointSelection(w, TextF_CursorPosition(tf),
				 event->xkey.time);
	  _XmTextFieldSetCursorPosition(tf, event,
					TextF_CursorPosition(tf),
					False, True);
	  cb.reason = XmCR_VALUE_CHANGED;
	  cb.event = event;
	  XtCallCallbackList((Widget) tf, TextF_ValueChangedCallback(tf),
			     (XtPointer) &cb);
	}
    } else if (TextF_CursorPosition(tf) - 1 >= 0) {
      if (_XmTextFieldReplaceText(tf, event, TextF_CursorPosition(tf) - 1,
				  TextF_CursorPosition(tf), NULL, 0, True)) {
	CheckDisjointSelection(w, TextF_CursorPosition(tf),
			       event->xkey.time);
	_XmTextFieldSetCursorPosition(tf, event, TextF_CursorPosition(tf), 
				      False, True);
	cb.reason = XmCR_VALUE_CHANGED;
	cb.event = event;
	XtCallCallbackList((Widget) tf, TextF_ValueChangedCallback(tf),
			   (XtPointer) &cb);
      }
    }  
  }
  _XmTextFieldDrawInsertionPoint(tf, True);
}

/* ARGSUSED */
static void 
DeleteNextChar(Widget w,
	       XEvent *event,
	       char **params,
	       Cardinal *num_params)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  XmAnyCallbackStruct cb;

  /* if pending delete is on and there is a selection */
  _XmTextFieldDrawInsertionPoint(tf, False);
  if (NeedsPendingDelete(tf)) (void) TextFieldRemove(w, event);
  else { 
    if (tf->text.has_primary &&
	tf->text.prim_pos_left != tf->text.prim_pos_right) {
      if (TextF_CursorPosition(tf) < tf->text.string_length)
	if (_XmTextFieldReplaceText(tf, event, TextF_CursorPosition(tf),
				    TextF_CursorPosition(tf) + 1, NULL, 0, 
				    True)) {
	  CheckDisjointSelection(w, TextF_CursorPosition(tf),
				 event->xkey.time);
	  _XmTextFieldSetCursorPosition(tf, event, 
					TextF_CursorPosition(tf), 
					False, True);
	  cb.reason = XmCR_VALUE_CHANGED;
	  cb.event = event;
	  XtCallCallbackList((Widget) tf, TextF_ValueChangedCallback(tf),
			     (XtPointer) &cb);
	}
    } else if (TextF_CursorPosition(tf) < tf->text.string_length)
      if (_XmTextFieldReplaceText(tf, event, TextF_CursorPosition(tf),
				  TextF_CursorPosition(tf) + 1, NULL,
				  0, True)) {
	CheckDisjointSelection(w, TextF_CursorPosition(tf),
			       event->xkey.time);
	_XmTextFieldSetCursorPosition(tf, event, 
				      TextF_CursorPosition(tf),
				      False, True);
	cb.reason = XmCR_VALUE_CHANGED;
	cb.event = event;
	XtCallCallbackList((Widget) tf, TextF_ValueChangedCallback(tf),
			   (XtPointer) &cb);
      }
  }
  _XmTextFieldDrawInsertionPoint(tf, True);
}

/* ARGSUSED */
static void 
DeletePrevWord(Widget w,
	       XEvent *event,
	       char **params,
	       Cardinal *num_params)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  XmTextPosition left, right;
  XmAnyCallbackStruct cb;

  /* if pending delete is on and there is a selection */
  _XmTextFieldDrawInsertionPoint(tf, False);
  if (NeedsPendingDelete(tf)) (void) TextFieldRemove(w, event);
  else { 
    FindPrevWord(tf, &left, &right);
    if (tf->text.has_primary &&
	tf->text.prim_pos_left != tf->text.prim_pos_right) {
      if (_XmTextFieldReplaceText(tf, event, left, TextF_CursorPosition(tf),
				  NULL, 0, True)) {
	CheckDisjointSelection(w, TextF_CursorPosition(tf),
			       event->xkey.time);
	_XmTextFieldSetCursorPosition(tf, event, 
				      TextF_CursorPosition(tf), 
				      False, True);
	cb.reason = XmCR_VALUE_CHANGED;
	cb.event = event;
	XtCallCallbackList((Widget) tf, TextF_ValueChangedCallback(tf),
			   (XtPointer) &cb);
      }
    } else if (TextF_CursorPosition(tf) - 1 >= 0)
      if (_XmTextFieldReplaceText(tf, event, left, TextF_CursorPosition(tf),
				  NULL, 0, True)) {
	CheckDisjointSelection(w, TextF_CursorPosition(tf),
			       event->xkey.time);
	_XmTextFieldSetCursorPosition(tf, event,
				      TextF_CursorPosition(tf),
				      False, True);
	cb.reason = XmCR_VALUE_CHANGED;
	cb.event = event;
	XtCallCallbackList((Widget) tf, TextF_ValueChangedCallback(tf),
			   (XtPointer) &cb);
      }
  }
  _XmTextFieldDrawInsertionPoint(tf, True);
}

/* ARGSUSED */
static void 
DeleteNextWord(Widget w,
	       XEvent *event,
	       char **params,
	       Cardinal *num_params)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  XmTextPosition left, right;
  XmAnyCallbackStruct cb;

  /* if pending delete is on and there is a selection */
  _XmTextFieldDrawInsertionPoint(tf, False);
  if (NeedsPendingDelete(tf)) (void) TextFieldRemove(w, event);
  else { 
    FindNextWord(tf, &left, &right);
    if (tf->text.has_primary &&
	tf->text.prim_pos_left != tf->text.prim_pos_right) {
      if (_XmTextFieldReplaceText(tf, event, TextF_CursorPosition(tf),
				  right, NULL, 0, True)) {
	CheckDisjointSelection(w, TextF_CursorPosition(tf),
			       event->xkey.time);
	_XmTextFieldSetCursorPosition(tf, event,
				      TextF_CursorPosition(tf),
				      False, True);
	cb.reason = XmCR_VALUE_CHANGED;
	cb.event = event;
	XtCallCallbackList((Widget) tf, TextF_ValueChangedCallback(tf),
			   (XtPointer) &cb);
      }
    } else if (TextF_CursorPosition(tf) < tf->text.string_length)
      if (_XmTextFieldReplaceText(tf, event, TextF_CursorPosition(tf),
				  right, NULL, 0, True)) {
	CheckDisjointSelection(w, TextF_CursorPosition(tf),
			       event->xkey.time);
	_XmTextFieldSetCursorPosition(tf, event, 
				      TextF_CursorPosition(tf), 
				      False, True);
	cb.reason = XmCR_VALUE_CHANGED;
	cb.event = event;
	XtCallCallbackList((Widget) tf, TextF_ValueChangedCallback(tf),
			   (XtPointer) &cb);
      }
  }
  _XmTextFieldDrawInsertionPoint(tf, True);
}


/* ARGSUSED */
static void 
DeleteToEndOfLine(Widget w,
		  XEvent *event,
		  char **params,
		  Cardinal *num_params)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  XmAnyCallbackStruct cb;

  /* if pending delete is on and there is a selection */
  _XmTextFieldDrawInsertionPoint(tf, False);
  if (NeedsPendingDelete(tf)) (void) TextFieldRemove(w, event);
  else if (TextF_CursorPosition(tf) < tf->text.string_length) {
    if (_XmTextFieldReplaceText(tf, event, TextF_CursorPosition(tf),
				tf->text.string_length, NULL, 0, True)) {
      CheckDisjointSelection(w, TextF_CursorPosition(tf),
			     event->xkey.time);
      _XmTextFieldSetCursorPosition(tf, event, TextF_CursorPosition(tf),
				    False, True);
      cb.reason = XmCR_VALUE_CHANGED;
      cb.event = event;
      XtCallCallbackList((Widget) tf, TextF_ValueChangedCallback(tf),
			 (XtPointer) &cb);
    }
  }
  _XmTextFieldDrawInsertionPoint(tf, True);
}


/* ARGSUSED */
static void 
DeleteToStartOfLine(Widget w,
		    XEvent *event,
		    char **params,
		    Cardinal *num_params)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  XmAnyCallbackStruct cb;

  /* if pending delete is on and there is a selection */
  _XmTextFieldDrawInsertionPoint(tf, False);
  if (NeedsPendingDelete(tf)) (void) TextFieldRemove(w, event);
  else if (TextF_CursorPosition(tf) - 1 >= 0) {
    if (_XmTextFieldReplaceText(tf, event, 0, 
			        TextF_CursorPosition(tf), NULL, 0, True)) {
      CheckDisjointSelection(w, TextF_CursorPosition(tf),
			     event->xkey.time);
      _XmTextFieldSetCursorPosition(tf, event, TextF_CursorPosition(tf),
				    False, True);
      cb.reason = XmCR_VALUE_CHANGED;
      cb.event = event;
      XtCallCallbackList((Widget) tf, TextF_ValueChangedCallback(tf),
			 (XtPointer) &cb);
    }
  }
  _XmTextFieldDrawInsertionPoint(tf, True);
}

/* ARGSUSED */
static void 
ProcessCancel(Widget w,
	      XEvent *event,
	      char **params,
	      Cardinal *num_params)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  
  XmParentInputActionRec  p_event;
  
  p_event.process_type = XmINPUT_ACTION;
  p_event.action = XmPARENT_CANCEL;
  p_event.event = event;/* Pointer to XEvent. */
  p_event.params = params; /* Or use what you have if   */
  p_event.num_params = num_params;/* input is from translation.*/
  
  _XmTextFieldDrawInsertionPoint(tf, False);
  if (tf->text.has_secondary) {
    tf->text.cancel = True;
    /* This will mark the has_secondary field to False. */
    _XmTextFieldSetSel2(w, 1, 0, False, event->xkey.time);
    XtUngrabKeyboard(w, CurrentTime);
  }
  
  if (tf->text.has_primary && tf->text.extending) {
    tf->text.cancel = True;
    /* reset orig_left and orig_right */
    _XmTextFieldStartSelection(tf, tf->text.orig_left,
			       tf->text.orig_right, event->xkey.time);
    tf->text.pending_off = False;
    _XmTextFieldSetCursorPosition(tf, NULL, tf->text.stuff_pos, True, True);
  }
  
  if (!tf->text.cancel)
    (void) _XmParentProcess(XtParent(tf), (XmParentProcessData) &p_event);
  
  if (tf->text.select_id) {
    XtRemoveTimeOut(tf->text.select_id);
    tf->text.select_id = 0;
  }
  _XmTextFieldDrawInsertionPoint(tf, True);
  
}

/* ARGSUSED */
static void 
Activate(Widget w,
	 XEvent *event,
	 char **params,
	 Cardinal *num_params)
{
  XmAnyCallbackStruct cb;
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  XmParentInputActionRec  p_event;
  
  p_event.process_type = XmINPUT_ACTION;
  p_event.action = XmPARENT_ACTIVATE;
  p_event.event = event;/* Pointer to XEvent. */
  p_event.params = params; /* Or use what you have if   */
  p_event.num_params = num_params;/* input is from translation.*/
  
  cb.reason = XmCR_ACTIVATE;
  cb.event  = event;
  XtCallCallbackList(w, TextF_ActivateCallback(tf), (XtPointer) &cb);
  
  (void) _XmParentProcess(XtParent(w), (XmParentProcessData) &p_event);
}

static void
SetAnchorBalancing(XmTextFieldWidget tf,
		   XmTextPosition position)
{
  XmTextPosition left = tf->text.prim_pos_left, right = tf->text.prim_pos_right;
  float bal_point;
  
  if (!tf->text.has_primary ||
      left == right) {
    tf->text.prim_anchor = position;
  } else {
    bal_point = (float)(((float)(right - left) / 2.0) + (float)left);
    
    /* shift anchor and direction to opposite end of the selection */
    if ((float)position < bal_point) {
      tf->text.prim_anchor = tf->text.orig_right;
    } else if ((float)position > bal_point) {
      tf->text.prim_anchor = tf->text.orig_left;
    }
  }
}

static void
SetNavigationAnchor(XmTextFieldWidget tf,
		    XmTextPosition old_position,
		    XmTextPosition new_position,
#if NeedWidePrototypes
		    int extend)
#else
                    Boolean extend)
#endif /* NeedWidePrototypes */
{
  XmTextPosition left = tf->text.prim_pos_left, 
                 right = tf->text.prim_pos_right;
  Boolean has_selection = tf->text.has_primary && left != right;
 
  if (!tf->text.add_mode) {
    if (extend) {
      if (old_position < left || old_position > right)
	/* start outside selection - anchor at start position */
	tf->text.prim_anchor = old_position;
      else if (!has_selection || left <= new_position && new_position <= right)
	/* no selection, or moving into selection */
	SetAnchorBalancing(tf, old_position);
      else
	/* moving to outside selection */
	SetAnchorBalancing(tf, new_position);
    } else {
      if (has_selection) {
	SetSelection(tf, old_position, old_position, True);
	tf->text.prim_anchor = old_position;
      }
    }
  } else if (extend) {
    if (old_position < left || old_position > right)
      /* start outside selection - anchor at start position */
      tf->text.prim_anchor = old_position;
    else if (!has_selection || left <= new_position && new_position <= right)
      /* no selection, or moving into selection */
      SetAnchorBalancing(tf, old_position);
    else
      /* moving to outside selection */
      SetAnchorBalancing(tf, new_position);
  }
}

static void
CompleteNavigation(XmTextFieldWidget tf,
		   XEvent *event,
		   XmTextPosition position,
		   Time time,
#if NeedWidePrototypes
		   int extend)
#else
                   Boolean extend)
#endif /* NeedWidePrototypes */
{
  XmTextPosition left = tf->text.prim_pos_left, right = tf->text.prim_pos_right;
  
  if ((tf->text.add_mode &&
       tf->text.has_primary &&
       position >= left && position <= right) || extend)
    tf->text.pending_off = FALSE;
  else
    tf->text.pending_off = TRUE;
  
  _XmTextFieldSetCursorPosition(tf, event, position, True, True);
  
  if (extend) {
    if (tf->text.prim_anchor > position) {
      left = position;
      right = tf->text.prim_anchor;
    } else {
      left = tf->text.prim_anchor;
      right = position;
    }
    _XmTextFieldStartSelection(tf, left, right, time);
    tf->text.pending_off = False;
    
    tf->text.orig_left = left;
    tf->text.orig_right = right;
  }
}

/* ARGSUSED */
static void 
SimpleMovement(Widget w,
	       XEvent *event,
	       String *params,
	       Cardinal *num_params,
	       XmTextPosition cursorPos,
	       XmTextPosition position)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  Boolean extend = False;
  int value;
  
  if (*num_params > 0)
  {
      /* There is only one valid reptype value for this reptype, i.e.
	 "extend". If we found a match then set the Boolean to true. */
      if (_XmConvertActionParamToRepTypeId((Widget) w,
			   XmRID_TEXTFIELD_EXTEND_MOVEMENT_ACTION_PARAMS,
			   params[0], False, &value) == True)
      {
	  extend = True;
      }
  }
  
  _XmTextFieldDrawInsertionPoint(tf, False);
  SetNavigationAnchor(tf, cursorPos, position, extend);
  CompleteNavigation(tf, event, position, event->xkey.time, extend);
  _XmTextFieldDrawInsertionPoint(tf, True);
}

/* ARGSUSED */
static void 
BackwardChar(Widget w,
	     XEvent *event,
	     char **params,
	     Cardinal *num_params)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  XmTextPosition cursorPos, position;
  
  cursorPos = TextF_CursorPosition(tf);
  
  if (cursorPos > 0) {
    _XmTextFieldDrawInsertionPoint(tf, False);
    position = cursorPos - 1;
    SimpleMovement((Widget) tf, event, params, num_params,
		   cursorPos, position);
    _XmTextFieldDrawInsertionPoint(tf, True);
  }
}

/* ARGSUSED */
static void 
ForwardChar(Widget w,
	    XEvent *event,
	    char **params,
	    Cardinal *num_params)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  XmTextPosition cursorPos, position;
  
  cursorPos = TextF_CursorPosition(tf);
  
  if (cursorPos < tf->text.string_length) {
    _XmTextFieldDrawInsertionPoint(tf, False);
    position = cursorPos + 1;
    SimpleMovement((Widget) tf, event, params, num_params,
		   cursorPos, position);
    _XmTextFieldDrawInsertionPoint(tf, True);
  }
}

/* ARGSUSED */
static void 
BackwardWord(Widget w,
	     XEvent *event,
	     char **params,
	     Cardinal *num_params)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  XmTextPosition cursorPos, position, dummy;
  
  cursorPos = TextF_CursorPosition(tf);
  
  if (cursorPos > 0) {
    _XmTextFieldDrawInsertionPoint(tf, False);
    FindPrevWord(tf, &position, &dummy);
    SimpleMovement((Widget) tf, event, params, num_params,
		   cursorPos, position);
    _XmTextFieldDrawInsertionPoint(tf, True);
  }
}

/* ARGSUSED */
static void 
ForwardWord(Widget w,
	    XEvent *event,
	    char **params,
	    Cardinal *num_params)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  XmTextPosition cursorPos, position, dummy;
  wchar_t white_space[3];
  
  if (tf->text.max_char_size != 1) {
    (void)mbtowc(&white_space[0], " ", 1);
    (void)mbtowc(&white_space[1], "\n", 1);
    (void)mbtowc(&white_space[2], "\t", 1);
  }
  
  cursorPos = TextF_CursorPosition(tf);
  
  _XmTextFieldDrawInsertionPoint(tf, False);
  if (cursorPos < tf->text.string_length) {
    if (tf->text.max_char_size == 1) {
      if (isspace((unsigned char)TextF_Value(tf)[cursorPos]))
	FindWord(tf, cursorPos, &dummy, &position);
      else
	FindNextWord(tf, &dummy, &position);
      if(isspace((unsigned char)TextF_Value(tf)[position])) {
	for (;position < tf->text.string_length; position++) {
	  if (!isspace((unsigned char)TextF_Value(tf)[position]))
	    break;
	}
      }
    } else {
      if (_XmTextFieldIsWSpace(TextF_WcValue(tf)[cursorPos],
			       white_space, 3))
	FindWord(tf, cursorPos, &dummy, &position);
      else
	FindNextWord(tf, &dummy, &position);
      if (_XmTextFieldIsWSpace(TextF_WcValue(tf)[position],
			       white_space, 3)) {
	for (; position < tf->text.string_length; position++) {
	  if (!_XmTextFieldIsWSpace(TextF_WcValue(tf)[position], 
				    white_space, 3))
	    break;
	}
      }
    }
    SimpleMovement((Widget) tf, event, params, num_params,
		   cursorPos, position);
  }
  _XmTextFieldDrawInsertionPoint(tf, True);
}


/* ARGSUSED */
static void 
EndOfLine(Widget w,
	  XEvent *event,
	  char **params,
	  Cardinal *num_params)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  XmTextPosition cursorPos, position;
  
  cursorPos = TextF_CursorPosition(tf);
  
  if (cursorPos < tf->text.string_length) {
    _XmTextFieldDrawInsertionPoint(tf, False);
    position = tf->text.string_length;
    SimpleMovement((Widget) tf, event, params, num_params,
		   cursorPos, position);
    _XmTextFieldDrawInsertionPoint(tf, True);
  }
}


/* ARGSUSED */
static void 
BeginningOfLine(Widget w,
		XEvent *event,
		char **params,
		Cardinal *num_params)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  XmTextPosition cursorPos, position;
  
  cursorPos = TextF_CursorPosition(tf);
  
  if (cursorPos > 0) {
    position = 0;
    _XmTextFieldDrawInsertionPoint(tf, False);
    SimpleMovement((Widget) tf, event, params, num_params,
		   cursorPos, position);
    _XmTextFieldDrawInsertionPoint(tf, True);
  }
}

static void 
SetSelection(XmTextFieldWidget tf,
	     XmTextPosition left,
	     XmTextPosition right,
#if NeedWidePrototypes
	     int redisplay)
#else
             Boolean redisplay)
#endif /* NeedWidePrototypes */
{
  XmTextPosition display_left, display_right;
  XmTextPosition old_prim_left, old_prim_right;
  
  if (left < 0) left = 0;
  if (right < 0) right = 0;
  
  if (left > tf->text.string_length)
    left = tf->text.string_length;
  if (right > tf->text.string_length)
    right = tf->text.string_length;
  
  if (left == right && tf->text.prim_pos_left != tf->text.prim_pos_right &&
      tf->text.add_mode) {
    _XmTextFieldDrawInsertionPoint(tf, False);
    tf->text.add_mode = False;
    _XmTextFieldDrawInsertionPoint(tf, True);
  }
  if (left == tf->text.prim_pos_left && right == tf->text.prim_pos_right)
    return;
  
  TextFieldSetHighlight(tf, tf->text.prim_pos_left,
			tf->text.prim_pos_right, XmHIGHLIGHT_NORMAL);
  
  old_prim_left = tf->text.prim_pos_left;
  old_prim_right = tf->text.prim_pos_right;
  
  if (left > right) {
    tf->text.prim_pos_left = right;
    tf->text.prim_pos_right = left;
  } else {
    tf->text.prim_pos_left = left;
    tf->text.prim_pos_right = right;
  }
  
  TextFieldSetHighlight(tf, tf->text.prim_pos_left,
			tf->text.prim_pos_right, XmHIGHLIGHT_SELECTED);
  
  if (redisplay) {
    if (old_prim_left > tf->text.prim_pos_left) {
      display_left = tf->text.prim_pos_left;
    } else if (old_prim_left < tf->text.prim_pos_left) {
      display_left = old_prim_left;
    } else
      display_left = (old_prim_right > tf->text.prim_pos_right) ?
	tf->text.prim_pos_right : old_prim_right;
    
    if (old_prim_right < tf->text.prim_pos_right) {
      display_right = tf->text.prim_pos_right;
    } else if (old_prim_right > tf->text.prim_pos_right) {
      display_right = old_prim_right;
    } else
      display_right = (old_prim_left < tf->text.prim_pos_left) ?
	tf->text.prim_pos_left : old_prim_left;
    
    if (display_left > tf->text.string_length)
      display_left = tf->text.string_length;

    if (display_right > tf->text.string_length)
      display_right = tf->text.string_length;

    RedisplayText(tf, display_left, display_right);
  }
  tf->text.refresh_ibeam_off = True;
}


/*
 * Begin the selection by gaining ownership of the selection
 * and setting the selection parameters.
 */
void 
_XmTextFieldStartSelection(XmTextFieldWidget tf,
			   XmTextPosition left,
			   XmTextPosition right,
			   Time sel_time)
{
  if (!XtIsRealized((Widget)tf)) return;
  
  /* if we don't already own the selection */
  if (tf->text.take_primary || 
      (tf->text.prim_pos_left == tf->text.prim_pos_right && left != right)) {
    if (!sel_time) sel_time = _XmValidTimestamp((Widget)tf);
    /* Try to gain ownership. */
    if (XmePrimarySource((Widget) tf, sel_time)) {
      XmAnyCallbackStruct cb;
      
      tf->text.prim_time = sel_time;
      _XmTextFieldDrawInsertionPoint(tf, False);
      if (tf->text.prim_pos_left != tf->text.prim_pos_right)
	doSetHighlight((Widget)tf, tf->text.prim_pos_left,
				tf->text.prim_pos_right, XmHIGHLIGHT_NORMAL);
      tf->text.has_primary = True; 
      tf->text.take_primary = False; 
      tf->text.prim_pos_left = tf->text.prim_pos_right =
	tf->text.prim_anchor = TextF_CursorPosition(tf);
      /*
       * Set the selection boundries for highlighting the text,
       * and marking the selection.
       */
      SetSelection(tf, left, right, True);
      
      _XmTextFieldDrawInsertionPoint(tf, True);
      
      /* Call the gain selection callback */
      cb.reason = XmCR_GAIN_PRIMARY;
      cb.event = NULL;
      XtCallCallbackList((Widget) tf, tf->text.gain_primary_callback, 
			 (XtPointer) &cb);
      
    } else 
      /*
       * Failed to gain ownership of the selection so make sure
       * the text does not think it owns the selection.
       * (this might be overkill)
       */
      _XmTextFieldDeselectSelection((Widget)tf, True, sel_time);
  } else {
    _XmTextFieldDrawInsertionPoint(tf, False);
    doSetHighlight((Widget)tf, tf->text.prim_pos_left,
			    tf->text.prim_pos_right, XmHIGHLIGHT_NORMAL);
    tf->text.prim_pos_left = tf->text.prim_pos_right =
      tf->text.prim_anchor = TextF_CursorPosition(tf);
    /*
     * Set the new selection boundries for highlighting the text,
     * and marking the selection.
     */
    SetSelection(tf, left, right, True);
    
    _XmTextFieldDrawInsertionPoint(tf, True);
  }
}

/* ARGSUSED */
static void 
ProcessHorizontalParams(Widget w,
			XEvent *event,
			char **params,
			Cardinal *num_params,
			XmTextPosition *left,
			XmTextPosition *right,
			XmTextPosition *position)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  XmTextPosition old_cursorPos = TextF_CursorPosition(tf);
  int direction;
  
  *position = TextF_CursorPosition(tf);
  
  if (!tf->text.has_primary || 
      (*left = tf->text.prim_pos_left) == (*right = tf->text.prim_pos_right)) {
    tf->text.orig_left = tf->text.orig_right = tf->text.prim_anchor;
    *left = *right = old_cursorPos;
  }
  
  if (*num_params > 0)
  {
      /* Process the parameters. We can only have a single parameter which
	 will be either "right" or "left". */
      if (_XmConvertActionParamToRepTypeId((Widget) w,
			   XmRID_TEXTFIELD_DIRECTION_ACTION_PARAMS,
			   params[0], False, &direction) == True)
      {
	  if (direction == _RIGHT) {
	      if (*position >= tf->text.string_length) return;
	      (*position)++;
	  }
	  else if (direction == _LEFT) {
	      if (*position <= 0) return;
	      (*position)--;
	  }
      }
  }
}


/* ARGSUSED */
static void 
ProcessSelectParams(Widget w,
		    XEvent *event,
		    XmTextPosition *left,
		    XmTextPosition *right,
		    XmTextPosition *position)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  
  *position = TextF_CursorPosition(tf);
  
  if (!tf->text.has_primary || 
      tf->text.prim_pos_left == tf->text.prim_pos_right) {
    if (*position > tf->text.prim_anchor) {
      *left = tf->text.prim_anchor;
      *right = *position;
    } else {
      *left = *position;
      *right = tf->text.prim_anchor;
    }
  }
}


/* ARGSUSED */
static void 
KeySelection(Widget w,
	     XEvent *event,
	     char **params,
	     Cardinal *num_params)
{
  XmTextPosition position, left, right;
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  XmTextPosition cursorPos;
  int direction;
 
  TextFieldResetIC(w);
  _XmTextFieldDrawInsertionPoint(tf,False); /* Turn off I beam blink
					       during selection */
  
  tf->text.orig_left = tf->text.prim_pos_left;
  tf->text.orig_right = tf->text.prim_pos_right;
  
  cursorPos = TextF_CursorPosition(tf);
  if (*num_params > 0)
  {
      /* Process the parameters. The only legal values are "right" and
	 "left". */
      if (_XmConvertActionParamToRepTypeId((Widget) w,
			   XmRID_TEXTFIELD_DIRECTION_ACTION_PARAMS,
			   params[0], False, &direction) == True)
      {
	  SetAnchorBalancing(tf, cursorPos);
      }
  }
  
  tf->text.extending = True;
  
  if (*num_params == 0)
  {
    position = cursorPos;
    ProcessSelectParams(w, event, &left, &right, &position);
  }
  else if (*num_params > 0) 
  { 
      /* Process the parameters. The only legal values are "right" and
	 "left". */
      if (_XmConvertActionParamToRepTypeId((Widget) w,
			   XmRID_TEXTFIELD_DIRECTION_ACTION_PARAMS,
			   params[0], False, &direction) == True)
      {
	  ProcessHorizontalParams(w, event, params, num_params, &left,
				  &right, &position);
      }
  }
  
  cursorPos = position;
  
  if (position < 0 || position > tf->text.string_length) {
    _XmTextFieldDrawInsertionPoint(tf,True); /* Turn on I beam now
						that we are done */
    tf->text.extending = False;
    return;
  }
  
  /* shift anchor and direction to opposite end of the selection */
  if (position > tf->text.prim_anchor) {
    right = cursorPos = position;
    left = tf->text.prim_anchor;
  } else {
    left = cursorPos = position;
    right = tf->text.prim_anchor;
  }
  
  if (left > right) {
    XmTextPosition tempIndex = left;
    left = right;
    right = tempIndex;
  }
  
  if (tf->text.take_primary)
    _XmTextFieldStartSelection(tf, left, right, event->xbutton.time);
  else
    SetSelection(tf, left, right, True);
  
  tf->text.pending_off = False;
  
  _XmTextFieldSetCursorPosition(tf, event, cursorPos, True, True);
  (void) SetDestination(w, cursorPos, False, event->xkey.time);
  
  tf->text.orig_left = tf->text.prim_pos_left;
  tf->text.orig_right = tf->text.prim_pos_right;

  tf->text.extending = False;
  _XmTextFieldDrawInsertionPoint(tf,True); /* Turn on I beam now
					      that we are done */
  
}

/* ARGSUSED */
static void 
TextFocusIn(Widget w,
	    XEvent *event,
	    char **params,
	    Cardinal *num_params)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  XmAnyCallbackStruct cb;
  XRectangle xmim_area;
  XPoint xmim_point;
  
  if (event->xfocus.send_event && !(tf->text.has_focus)) {
    tf->text.has_focus = True;
    _XmTextFieldDrawInsertionPoint(tf, False);
    tf->text.blink_on = False;
    
    tf->text.refresh_ibeam_off = True;
    if (_XmGetFocusPolicy(w) == XmEXPLICIT) {
      if (((XmTextFieldWidgetClass)
	   XtClass(w))->primitive_class.border_highlight) {
	(*((XmTextFieldWidgetClass)
	   XtClass(w))->primitive_class.border_highlight)(w);
      } 
      if (!tf->text.has_destination && !tf->text.sel_start)
	(void) SetDestination(w, TextF_CursorPosition(tf), False,
			      XtLastTimestampProcessed(XtDisplay(w)));
    }
    if (XtIsSensitive(w)) ChangeBlinkBehavior(tf, True);
    _XmTextFieldDrawInsertionPoint(tf, True);
    (void) GetXYFromPos(tf, TextF_CursorPosition(tf),
			&xmim_point.x, &xmim_point.y);
    (void)TextFieldGetDisplayRect((Widget)tf, &xmim_area);
    XmImVaSetFocusValues(w, XmNspotLocation, &xmim_point, 
			 XmNarea, &xmim_area, NULL);
    
    cb.reason = XmCR_FOCUS;
    cb.event = event;
    XtCallCallbackList (w, tf->text.focus_callback, (XtPointer) &cb);
  }
  
  _XmPrimitiveFocusIn(w, event, params, num_params);
}


/* ARGSUSED */
static void 
TextFocusOut(Widget w,
	     XEvent *event,
	     char **params,
	     Cardinal *num_params)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  
  if (event->xfocus.send_event && tf->text.has_focus) {
    ChangeBlinkBehavior(tf, False);
    _XmTextFieldDrawInsertionPoint(tf, False);
    tf->text.has_focus = False;
    tf->text.blink_on = True;
    _XmTextFieldDrawInsertionPoint(tf, True);
    if (((XmTextFieldWidgetClass) XtClass(tf))
	->primitive_class.border_unhighlight) {
      (*((XmTextFieldWidgetClass) XtClass(tf))
       ->primitive_class.border_unhighlight)((Widget) tf);
    } 
    XmImUnsetFocus(w);
  }
  
  /* If traversal is on, then the leave verification callback is called in
     the traversal event handler */
  if (event->xfocus.send_event && !tf->text.traversed &&
      _XmGetFocusPolicy(w) == XmEXPLICIT) {
    if (!VerifyLeave(tf, event)) {
      if (tf->text.verify_bell) XBell(XtDisplay(w), 0);
      return;
    }
  } else
    if (tf->text.traversed) {
      tf->text.traversed = False;
    }
}

static void 
SetScanIndex(XmTextFieldWidget tf,
	     XEvent *event)
{
  Time sel_time;
  
  if (event->type == ButtonPress) sel_time = event->xbutton.time;
  else sel_time = event->xkey.time;
  
  
  if (sel_time > tf->text.last_time &&
      sel_time - tf->text.last_time < XtGetMultiClickTime(XtDisplay(tf))) {
    /*
     * Fix for HaL DTS 9841 - Increment the sarray_index first, then check to 
     *			  see if it is greater that the count.  Otherwise,
     *			  an error will occur.
     */
    tf->text.sarray_index++;
    if (tf->text.sarray_index >= TextF_SelectionArrayCount(tf)) {
      tf->text.sarray_index = 0;
    }
    /*
     * End fix for HaL DTS 9841
     */
  } else
    tf->text.sarray_index = 0;
  
  tf->text.last_time = sel_time;
}
    
static void 
ExtendScanSelection(XmTextFieldWidget tf,
		    XEvent *event)
{
  XmTextPosition pivot_left, pivot_right;
  XmTextPosition left = tf->text.prim_pos_left, right = tf->text.prim_pos_right;
  XmTextPosition new_position = GetPosFromX(tf, (Position) event->xbutton.x);
  XmTextPosition cursorPos = TextF_CursorPosition(tf);
  Boolean pivot_modify = False;
  float bal_point;
  
  if (!tf->text.has_primary ||
      left == right) {
    tf->text.orig_left = tf->text.orig_right =
      tf->text.prim_anchor = TextF_CursorPosition(tf);
    bal_point = (XmTextPosition) tf->text.prim_anchor ;
  } else
    bal_point = (float)(((float)(right - left) / 2.0) + (float)left);
  
  if (!tf->text.extending)
    if ((float)new_position < bal_point) {
      tf->text.prim_anchor = tf->text.orig_right;
    } else if ((float)new_position > bal_point) {
      tf->text.prim_anchor = tf->text.orig_left;
    }
  
  tf->text.extending = True;
  
  switch (TextF_SelectionArray(tf)[tf->text.sarray_index]) {
  case XmSELECT_POSITION:
    if (tf->text.take_primary && new_position != tf->text.prim_anchor)
      _XmTextFieldStartSelection(tf, tf->text.prim_anchor,
				 new_position, event->xbutton.time);
    else if (tf->text.has_primary)
      SetSelection(tf, tf->text.prim_anchor, new_position, True);
    tf->text.pending_off = False;
    cursorPos = new_position;
    break;
  case XmSELECT_WHITESPACE:
  case XmSELECT_WORD:
    FindWord(tf, new_position, &left, &right);
    FindWord(tf, tf->text.prim_anchor,
	     &pivot_left, &pivot_right);
    tf->text.pending_off = False;
    if (left != pivot_left || right != pivot_right) {
      if (left > pivot_left)
	left = pivot_left;
      if (right < pivot_right)
	right = pivot_right;
      pivot_modify = True;
    }
    if (tf->text.take_primary)
      _XmTextFieldStartSelection(tf, left, right, event->xbutton.time);
    else
      SetSelection(tf, left, right, True);
    
    if (pivot_modify) {
      if ((((right - left) / 2) + left) <= new_position) {
	cursorPos = right;
      } else
	cursorPos = left;
    } else {
      if (left >= TextF_CursorPosition(tf))
	cursorPos = left;
      else
	cursorPos = right;
    }
    break;
  default:
    break;
  }
  if (cursorPos != TextF_CursorPosition(tf)) {
    (void) SetDestination((Widget)tf, cursorPos, False, event->xkey.time);
    _XmTextFieldSetCursorPosition(tf, event, cursorPos, True, True);
  }
}

static void 
SetScanSelection(XmTextFieldWidget tf,
		 XEvent *event)
{
  XmTextPosition left, right;
  XmTextPosition new_position = 0;
  XmTextPosition cursorPos = TextF_CursorPosition(tf);
  Position dummy = 0;
  Boolean update_position = False;
  
  SetScanIndex(tf, event);
  
  if (event->type == ButtonPress)
    new_position = GetPosFromX(tf, (Position) event->xbutton.x);
  else
    new_position = TextF_CursorPosition(tf);
  
  _XmTextFieldDrawInsertionPoint(tf,False); /* Turn off I beam
					       blink during selection */
  
  switch (TextF_SelectionArray(tf)[tf->text.sarray_index]) {
  case XmSELECT_POSITION:
    tf->text.prim_anchor = new_position;
    if (tf->text.has_primary) {
      SetSelection(tf, new_position, new_position, True);
      tf->text.pending_off = False;
    }
    cursorPos = new_position;
    update_position = True;
    break;
  case XmSELECT_WHITESPACE:
  case XmSELECT_WORD:
    FindWord(tf, TextF_CursorPosition(tf), &left, &right);
    if (tf->text.take_primary)
      _XmTextFieldStartSelection(tf, left, right, event->xbutton.time);
    else
      SetSelection(tf, left, right, True);
    tf->text.pending_off = False;
    if ((((right - left) / 2) + left) <= new_position)
      cursorPos = right;
    else
      cursorPos = left;
    break;
  case XmSELECT_LINE:
  case XmSELECT_OUT_LINE:
  case XmSELECT_PARAGRAPH:
  case XmSELECT_ALL:
    if (tf->text.take_primary)
      _XmTextFieldStartSelection(tf, 0, tf->text.string_length,
				 event->xbutton.time);
    else
      SetSelection(tf, 0, tf->text.string_length, True);
    tf->text.pending_off = False;
    if (event->type == ButtonPress)
      if ((tf->text.string_length) / 2 <= new_position)
	cursorPos = tf->text.string_length;
      else
	cursorPos = 0;
    break;
  }
  
  (void) SetDestination((Widget)tf, cursorPos, False, event->xkey.time);
  if (cursorPos != TextF_CursorPosition(tf) || update_position) {
    _XmTextFieldSetCursorPosition(tf, event, cursorPos, True, True);
  } 
  GetXYFromPos(tf, cursorPos, &(tf->text.select_pos_x),
	       &dummy);
  _XmTextFieldDrawInsertionPoint(tf,True);
}


/* ARGSUSED */
static void 
StartPrimary(Widget w,
	     XEvent *event,
	     char **params,
	     Cardinal *num_params)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;

  TextFieldResetIC(w);
  if (!tf->text.has_focus && _XmGetFocusPolicy(w) == XmEXPLICIT)
    (void) XmProcessTraversal(w, XmTRAVERSE_CURRENT);
  
  _XmTextFieldDrawInsertionPoint(tf,False);
  SetScanSelection(tf, event); /* use scan type to set the selection */
  tf->text.stuff_pos = TextF_CursorPosition(tf);
  _XmTextFieldDrawInsertionPoint(tf,True);
}


/* ARGSUSED */
static void 
MoveDestination(Widget w,
		XEvent *event,
		char **params,
		Cardinal *num_params)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  XmTextPosition left = tf->text.prim_pos_left, 
                 right = tf->text.prim_pos_right;
  XmTextPosition new_position;
  Boolean old_has_focus = tf->text.has_focus;
  Boolean reset_cursor = False;
  
  TextFieldResetIC(w);
  new_position = GetPosFromX(tf, (Position) event->xbutton.x);
  
  _XmTextFieldDrawInsertionPoint(tf, False);
  if (tf->text.has_primary && (right != left))
    (void) SetDestination(w, new_position, False, event->xbutton.time);
  
  tf->text.pending_off = False;
  
  if (!tf->text.has_focus && _XmGetFocusPolicy(w) == XmEXPLICIT)
    (void) XmProcessTraversal(w, XmTRAVERSE_CURRENT);
  
  /* Doing the the MoveDestination caused a traversal into my, causing
   * me to gain focus... Cursor is now on when it shouldn't be. */
  if ((reset_cursor = !old_has_focus && tf->text.has_focus) != False)
    _XmTextFieldDrawInsertionPoint(tf, False);
  
  _XmTextFieldSetCursorPosition(tf, event, new_position,
				True, True);
  if (new_position < left && new_position > right)
    tf->text.pending_off = True;
  
  /*
   * if cursor was turned off as a result of the focus state changing
   * then we need to undo the decrement to the cursor_on variable
   * by redrawing the insertion point.
   */
  if (reset_cursor)
    _XmTextFieldDrawInsertionPoint(tf, True);
  _XmTextFieldDrawInsertionPoint(tf, True);
}


/* ARGSUSED */
static void 
ExtendPrimary(Widget w,
	      XEvent *event,
	      char **params,
	      Cardinal *num_params)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;

  TextFieldResetIC(w);
  
  if (tf->text.cancel) return;
  
  _XmTextFieldDrawInsertionPoint(tf, False);
  tf->text.do_drop = False;
  
  if (event->type == ButtonPress)
    tf->text.stuff_pos = TextF_CursorPosition(tf);

  if (!CheckTimerScrolling(w, event)) {
    if (event->type == ButtonPress)
      DoExtendedSelection(w, event->xbutton.time);
    else
      DoExtendedSelection(w, event->xkey.time);
  } else
    ExtendScanSelection(tf, event); /* use scan type to set the selection */

  _XmTextFieldDrawInsertionPoint(tf, True);
}


/* ARGSUSED */
static void 
ExtendEnd(Widget w,
	  XEvent *event,
	  char **params,
	  Cardinal *num_params)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  
  
  if (tf->text.prim_pos_left == 0 && tf->text.prim_pos_right == 0)
    tf->text.orig_left = tf->text.orig_right = TextF_CursorPosition(tf);
  else {
    tf->text.orig_left = tf->text.prim_pos_left;
    tf->text.orig_right = tf->text.prim_pos_right;
    tf->text.cancel = False;
  }
  
  if (tf->text.select_id) {
    XtRemoveTimeOut(tf->text.select_id);
    tf->text.select_id = 0;
  }
  tf->text.select_pos_x = 0;
  tf->text.extending = False;
}

/* ARGSUSED */
static void
DoExtendedSelection(Widget w,
		    Time time)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  XmTextPosition position, cursorPos;
  XmTextPosition left = tf->text.prim_pos_left, right = tf->text.prim_pos_right;
  XmTextPosition pivot_left, pivot_right;
  Boolean pivot_modify = False;
  float bal_point;
  
  if (tf->text.cancel) {
    if (tf->text.select_id) 
	{
        XtRemoveTimeOut(tf->text.select_id);
        tf->text.select_id = 0;
	}
    return;
  }
  
  cursorPos = TextF_CursorPosition(tf);
  _XmTextFieldDrawInsertionPoint(tf, False);
  if (!tf->text.has_primary || left == right) {
    tf->text.prim_anchor = tf->text.cursor_position;
    left = right = TextF_CursorPosition(tf);
    tf->text.orig_left = tf->text.orig_right = tf->text.prim_anchor;
    bal_point = tf->text.prim_anchor;
  } else
    bal_point = (float)(((float)(tf->text.orig_right - tf->text.orig_left)
			 / 2.0) + (float)tf->text.orig_left);
  
  position = GetPosFromX(tf, tf->text.select_pos_x);
  
  if (!tf->text.extending)
    if ((float)position < bal_point) {
      tf->text.prim_anchor = tf->text.orig_right;
    } else if ((float)position > bal_point) {
      tf->text.prim_anchor = tf->text.orig_left;
    }
  
  tf->text.extending = True;
  
  /* Extend selection in same way as ExtendScan would do */
  
  switch (TextF_SelectionArray(tf)[tf->text.sarray_index]) {
  case XmSELECT_POSITION:
    if (tf->text.take_primary && position != tf->text.prim_anchor)
      _XmTextFieldStartSelection(tf, tf->text.prim_anchor,
				 position, time);
    else if (tf->text.has_primary)
      SetSelection(tf, tf->text.prim_anchor, position, True);
    tf->text.pending_off = False;
    cursorPos = position;
    break;
  case XmSELECT_WHITESPACE:
  case XmSELECT_WORD:
    FindWord(tf, position, &left, &right);
    FindWord(tf, tf->text.prim_anchor,
	     &pivot_left, &pivot_right);
    tf->text.pending_off = False;
    if (left != pivot_left || right != pivot_right) {
      if (left > pivot_left)
	left = pivot_left;
      if (right < pivot_right)
	right = pivot_right;
      pivot_modify = True;
    }
    if (tf->text.take_primary)
      _XmTextFieldStartSelection(tf, left, right, time);
    else
      SetSelection(tf, left, right, True);
    
    if (pivot_modify) {
      if ((((right - left) / 2) + left) <= position) {
	cursorPos = right;
      } else
	cursorPos = left;
    } else {
      if (left >= TextF_CursorPosition(tf))
	cursorPos = left;
      else
	cursorPos = right;
    }
    break;
  default:
    break;
  }
  if (cursorPos != TextF_CursorPosition(tf)) {
    (void) SetDestination((Widget)tf, cursorPos, False, time);
    _XmTextFieldSetCursorPosition(tf, NULL, cursorPos, True, True);
  }
  _XmTextFieldDrawInsertionPoint(tf, True);
}

/* ARGSUSED */
static void
DoSecondaryExtend(Widget w,
		  Time ev_time)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  
  XmTextPosition position = GetPosFromX(tf, tf->text.select_pos_x);
  
  if (tf->text.cancel) return;
  
  if (position < tf->text.sec_anchor) {
    if (tf->text.sec_pos_left > 0) 
      _XmTextFieldSetSel2(w, position, tf->text.sec_anchor, False, ev_time);
    if (tf->text.sec_pos_left >= 0) AdjustText(tf, tf->text.sec_pos_left, True);
  } else if (position > tf->text.sec_anchor) {
    if (tf->text.sec_pos_right < tf->text.string_length)
      _XmTextFieldSetSel2(w, tf->text.sec_anchor, position, False, ev_time);
    if (tf->text.sec_pos_right >= 0) 
      AdjustText(tf, tf->text.sec_pos_right, True);
  } else {
    _XmTextFieldSetSel2(w, position, position, False, ev_time);
    if (position >= 0) AdjustText(tf, position, True);
  }

  tf->text.sec_extending = True;
}



/************************************************************************
 *                                                                      *
 * BrowseScroll - timer proc that scrolls the list if the user has left *
 *              the window with the button down. If the button has been *
 *              released, call the standard click stuff.                *
 *                                                                      *
 ************************************************************************/
/* ARGSUSED */
static void
BrowseScroll(XtPointer closure,
	     XtIntervalId *id)
{
  Widget w = (Widget) closure;
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  
  if (tf->text.cancel) {
    tf->text.select_id = 0;
    return;
  }
  
  if (!tf->text.select_id) return;
  
  _XmTextFieldDrawInsertionPoint(tf, False);
  if (tf->text.sec_extending)
    DoSecondaryExtend(w, XtLastTimestampProcessed(XtDisplay(w)));
  else if (tf->text.extending)
    DoExtendedSelection(w, XtLastTimestampProcessed(XtDisplay(w)));
  
  XSync (XtDisplay(w), False);
  
  _XmTextFieldDrawInsertionPoint(tf, True);
  
  tf->text.select_id = XtAppAddTimeOut(XtWidgetToApplicationContext(w),
				       (unsigned long) PRIM_SCROLL_INTERVAL,
				       BrowseScroll, (XtPointer) w);
}


/* ARGSUSED */
static Boolean
CheckTimerScrolling(Widget w,
		    XEvent *event)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  Dimension margin_size = TextF_MarginWidth(tf) +
    tf->primitive.shadow_thickness +
      tf->primitive.highlight_thickness;
  Dimension top_margin = TextF_MarginHeight(tf) +
    tf->primitive.shadow_thickness +
      tf->primitive.highlight_thickness;
  
  tf->text.select_pos_x = event->xmotion.x;
  
  if ((event->xmotion.x > (int) margin_size) &&
      (event->xmotion.x < (int) (tf->core.width - margin_size))  &&
      (event->xmotion.y > (int) top_margin) &&
      (event->xmotion.y < (int) (top_margin + TextF_FontAscent(tf) +
                                 TextF_FontDescent(tf)))) {
    
    if (tf->text.select_id) {
      XtRemoveTimeOut(tf->text.select_id);
      tf->text.select_id = 0;
    }
  } else {
    /* to the left of the text */
    if (event->xmotion.x <= (int) margin_size)
      tf->text.select_pos_x = (Position) (margin_size -
                                          (tf->text.average_char_width + 1));
    /* to the right of the text */
    else if (event->xmotion.x >= (int) (tf->core.width - margin_size))
      tf->text.select_pos_x = (Position) ((tf->core.width - margin_size) +
					  tf->text.average_char_width + 1);
    if (!tf->text.select_id)
      tf->text.select_id = XtAppAddTimeOut(XtWidgetToApplicationContext(w),
					   (unsigned long) SEC_SCROLL_INTERVAL,
					   BrowseScroll, (XtPointer) w);
    return True;
  }
  return False;
}

static void 
RestorePrimaryHighlight(XmTextFieldWidget tf,
			XmTextPosition prim_left,
			XmTextPosition prim_right)
{
  if (tf->text.sec_pos_right >= prim_left &&
      tf->text.sec_pos_right <= prim_right) {
    /* secondary selection is totally inside primary selection */
    if (tf->text.sec_pos_left >= prim_left) {
      TextFieldSetHighlight(tf, prim_left, tf->text.sec_pos_left,
                            XmHIGHLIGHT_SELECTED);
      TextFieldSetHighlight(tf, tf->text.sec_pos_left,
			    tf->text.sec_pos_right,
			    XmHIGHLIGHT_NORMAL);
      TextFieldSetHighlight(tf, tf->text.sec_pos_right, prim_right,
			    XmHIGHLIGHT_SELECTED);
      /* right side of secondary selection is inside primary selection */
    } else {
      TextFieldSetHighlight(tf, tf->text.sec_pos_left, prim_left,
			    XmHIGHLIGHT_NORMAL);
      TextFieldSetHighlight(tf, prim_left, tf->text.sec_pos_right,
			    XmHIGHLIGHT_SELECTED);
    }
  } else {
    /* left side of secondary selection is inside primary selection */
    if (tf->text.sec_pos_left <= prim_right &&
	tf->text.sec_pos_left >= prim_left) {
      TextFieldSetHighlight(tf, tf->text.sec_pos_left, prim_right,
			    XmHIGHLIGHT_SELECTED);
      TextFieldSetHighlight(tf, prim_right, tf->text.sec_pos_right,
			    XmHIGHLIGHT_NORMAL);
    } else  {
      /* secondary selection encompasses the primary selection */
      if (tf->text.sec_pos_left <= prim_left &&
	  tf->text.sec_pos_right >= prim_right) {
	TextFieldSetHighlight(tf, tf->text.sec_pos_left, prim_left,
			      XmHIGHLIGHT_NORMAL);
	TextFieldSetHighlight(tf, prim_left, prim_right,
			      XmHIGHLIGHT_SELECTED);
	TextFieldSetHighlight(tf, prim_right, tf->text.sec_pos_right,
			      XmHIGHLIGHT_NORMAL);
	/* secondary selection is outside primary selection */
      } else {
	TextFieldSetHighlight(tf, prim_left, prim_right,
			      XmHIGHLIGHT_SELECTED);
	TextFieldSetHighlight(tf, tf->text.sec_pos_left,
			      tf->text.sec_pos_right,
			      XmHIGHLIGHT_NORMAL);
      }
    }
  }
}

void 
_XmTextFieldSetSel2(Widget w,
		    XmTextPosition left,
		    XmTextPosition right,
#if NeedWidePrototypes
		    int disown,
#else
		    Boolean disown,
#endif /* NeedWidePrototypes */
		    Time sel_time)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  Boolean result;
  
  if (tf->text.has_secondary) {
    if (left == tf->text.sec_pos_left && right == tf->text.sec_pos_right)
      return;
    
    /* If the widget has the primary selection, make sure the selection
     * highlight is restored appropriately.
     */
    if (tf->text.has_primary)
      RestorePrimaryHighlight(tf, tf->text.prim_pos_left, 
			      tf->text.prim_pos_right);
    else
      TextFieldSetHighlight(tf, tf->text.sec_pos_left,
			    tf->text.sec_pos_right, XmHIGHLIGHT_NORMAL);
  }
  
  if (left < right) {
    if (!tf->text.has_secondary) {
      if (!sel_time) sel_time = _XmValidTimestamp(w);
      result = XmeSecondarySource(w, sel_time);
      tf->text.sec_time = sel_time;
      tf->text.has_secondary = result;
      if (result) {
	tf->text.sec_pos_left = left;
	tf->text.sec_pos_right = right;
      } 
    } else {
      tf->text.sec_pos_left = left;
      tf->text.sec_pos_right = right;
    }
    tf->text.sec_drag = True;
  } else {
    if (left > right)
      tf->text.has_secondary = False;
    tf->text.sec_pos_left = tf->text.sec_pos_right = left;
    if (disown) {
      if (!sel_time) sel_time = _XmValidTimestamp(w);
      XtDisownSelection(w, XA_SECONDARY, sel_time);
      tf->text.has_secondary = False;
    }
  }
  
  TextFieldSetHighlight((XmTextFieldWidget) w, tf->text.sec_pos_left,
			tf->text.sec_pos_right, 
			XmHIGHLIGHT_SECONDARY_SELECTED);
  
  /* This can be optimized for performance enhancement */
  
  RedisplayText(tf, 0, tf->text.string_length);
}

/* ARGSUSED */
static void
StartDrag(Widget w,
	  XEvent *event,
	  String *params,
	  Cardinal *num_params)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  Widget drag_icon;
  Arg args[6];
  int n;
  
  drag_icon = XmeGetTextualDragIcon(w);
  
  n = 0;
  XtSetArg(args[n], XmNcursorBackground, tf->core.background_pixel);  n++;
  XtSetArg(args[n], XmNcursorForeground, tf->primitive.foreground);  n++; 
  XtSetArg(args[n], XmNsourceCursorIcon, drag_icon);  n++;
  if (TextF_Editable(tf)) {
    XtSetArg(args[n], XmNdragOperations, (XmDROP_MOVE | XmDROP_COPY)); n++;
  } else {
    XtSetArg(args[n], XmNdragOperations, XmDROP_COPY); n++;
  }
  (void) XmeDragSource(w, (XtPointer) w, event, args, n);
}

/*ARGSUSED*/
static	void
DragStart(XtPointer data,
	  XtIntervalId *id)	/* unused */
{
  XmTextFieldWidget tf = (XmTextFieldWidget)data;

  tf->text.drag_id = 0;
  StartDrag((Widget)tf, tf->text.transfer_action->event, 
	    tf->text.transfer_action->params, 
	    tf->text.transfer_action->num_params);
}

/* ARGSUSED */
static void 
StartSecondary(Widget w,
	       XEvent *event,
	       char **params,
	       Cardinal *num_params)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  XmTextPosition position = GetPosFromX(tf, (Position) event->xbutton.x);
  int status;
  
  tf->text.sel_start = True;
  XAllowEvents(XtDisplay(w), AsyncBoth, event->xbutton.time);
  tf->text.sec_anchor = position;
  tf->text.selection_move = FALSE;
  tf->text.selection_link = FALSE;
  
  status = XtGrabKeyboard(w, False, GrabModeAsync, GrabModeAsync,
			  event->xbutton.time);
  
  if (status != GrabSuccess)
    XmeWarning(w, GRABKBDERROR);
}


/* ARGSUSED */
static void
ProcessBDrag(Widget w,
	     XEvent *event,
	     char **params,
	     Cardinal *num_params)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;

  TextFieldResetIC(w);
  if (tf->text.extending)
    return;
  
   /* if the user has clicked twice very quickly, don't lose the original left
   ** position
   */
   if (!tf->text.has_secondary || (tf->text.sec_pos_left == tf->text.sec_pos_right))
    tf->text.sec_pos_left = GetPosFromX(tf, (Position) event->xbutton.x);

  _XmTextFieldDrawInsertionPoint(tf, False);
  if (InSelection(w, event)) {
    tf->text.sel_start = False;
    StartDrag(w, event, params, num_params);
  } else {
    StartSecondary(w, event, params, num_params);
  }
  _XmTextFieldDrawInsertionPoint(tf, True);
}

static void
ProcessBDragEvent(Widget w,
		  XEvent *event,
		  String *params,
		  Cardinal *num_params)
{
  XtEnum drag_on_btn1 = XmOFF;
  XmDisplay dpy;

  dpy = (XmDisplay) XmGetXmDisplay(XtDisplay(w));
  drag_on_btn1 = dpy->display.enable_btn1_transfer;

  if (drag_on_btn1 == XmBUTTON2_ADJUST && *num_params > 0) 
    XtCallActionProc(w, params[0], event, NULL, 0);
  else if (*num_params > 1)
    XtCallActionProc(w, params[1], event, NULL, 0);
}

/* ARGSUSED */
static Boolean
InSelection(Widget w,
	    XEvent *event)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  XmTextPosition position;
  XmTextPosition left = tf->text.prim_pos_left, 
                 right = tf->text.prim_pos_right;
  Position left_x, right_x, dummy;
   
  position = GetPosFromX(tf, (Position) event->xbutton.x);
  
  return (tf->text.has_primary && 
	  left != right &&
	  ( (position > left && position < right) ||
	    ( position == left &&
	      GetXYFromPos(tf, left, &left_x, &dummy) &&
	      event->xbutton.x > left_x) ||
	    ( position == right &&
	      GetXYFromPos(tf, right, &right_x, &dummy) &&
	      event->xbutton.x < right_x)));
}

/* ARGSUSED */
static void
ProcessBSelect(Widget w,
	       XEvent *event,
	       char **params,
	       Cardinal *num_params)
{
#define ABS_DELTA(x1, x2) (x1 < x2 ? x2 - x1 : x1 - x2)

  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  XtEnum drag_on_btn1 = XmOFF;
  Time event_time = event->xbutton.time;
  XmDisplay dpy;

  dpy = (XmDisplay) XmGetXmDisplay(XtDisplay(w));
  drag_on_btn1 = dpy->display.enable_btn1_transfer;

  if (!drag_on_btn1) {
    if (*num_params > 0)
      XtCallActionProc(w, params[0], event, NULL, 0);
    return;
  }

  if (*num_params == 0) {
    if (event->type == ButtonPress &&
	InSelection(w, event))
      StartDrag(w, event, params, num_params);
  } else {
    switch (event->type) {
    case ButtonPress:
      if (!InSelection(w, event) ||
	  (event_time > tf->text.last_time &&
	   event_time - tf->text.last_time < 
	   XtGetMultiClickTime(XtDisplay(w)))) {
	if (*num_params > 0)
	  XtCallActionProc(w, params[0], event, NULL, 0);
      } else {
	if (tf->text.drag_id) 
	  XtRemoveTimeOut(tf->text.drag_id);
	if (tf->text.transfer_action == NULL) {
	  tf->text.transfer_action = 
	    (_XmTextActionRec *) XtMalloc(sizeof(_XmTextActionRec));
	  tf->text.transfer_action->event = (XEvent *)XtMalloc(sizeof(XEvent));
	}
	memcpy((void *)tf->text.transfer_action->event, (void *)event,
	       sizeof(XEvent));
	tf->text.transfer_action->params = params;
	tf->text.transfer_action->num_params = num_params;
	tf->text.drag_id = XtAppAddTimeOut(XtWidgetToApplicationContext(w),
					   XtGetMultiClickTime(XtDisplay(w)),
					   DragStart, (XtPointer)w);
      }
      break;
    case ButtonRelease:
      if (tf->text.drag_id) {
	XtRemoveTimeOut(tf->text.drag_id);
	tf->text.drag_id = 0;
	if (*tf->text.transfer_action->num_params) {
	  XtCallActionProc(w, tf->text.transfer_action->params[0], 
			   tf->text.transfer_action->event, NULL, 0);
	}
      }
      XtCallActionProc(w, params[0], event, NULL, 0);
      break;
    case MotionNotify:
      if (tf->text.drag_id) {	
	XEvent *press = tf->text.transfer_action->event;
	if (ABS_DELTA(press->xbutton.x_root, event->xmotion.x_root) > 
	    tf->text.threshold ||
	    ABS_DELTA(press->xbutton.y_root, event->xmotion.y_root) > 
	    tf->text.threshold) {
	  XtRemoveTimeOut(tf->text.drag_id);
	  tf->text.drag_id = 0;
	  StartDrag(w, event, params, num_params);
	}
      } else if (*num_params > 0)
	XtCallActionProc(w, params[0], event, NULL, 0);
      break;
    }
  }
}

static void
ProcessBSelectEvent(Widget w,
		  XEvent *event,
		  String *params,
		  Cardinal *num_params)
{
  XtEnum drag_on_btn1 = XmOFF;
  XmDisplay dpy;

  dpy = (XmDisplay) XmGetXmDisplay(XtDisplay(w));
  drag_on_btn1 = dpy->display.enable_btn1_transfer;

  if (drag_on_btn1 == XmBUTTON2_TRANSFER && *num_params > 0) 
    XtCallActionProc(w, params[0], event, NULL, 0);
  else if (*num_params > 1)
    XtCallActionProc(w, params[1], event, NULL, 0);
}

/* ARGSUSED */
static void 
ExtendSecondary(Widget w,
		XEvent *event,
		char **params,
		Cardinal *num_params)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  XmTextPosition position = GetPosFromX(tf, (Position) event->xbutton.x);
  
  TextFieldResetIC(w);

  if (tf->text.cancel) return;
  
  _XmTextFieldDrawInsertionPoint(tf, False);
  if (position < tf->text.sec_anchor) {
    _XmTextFieldSetSel2(w, position, tf->text.sec_anchor,
			False, event->xbutton.time);
  } else if (position > tf->text.sec_anchor) {
    _XmTextFieldSetSel2(w, tf->text.sec_anchor, position, 
			False, event->xbutton.time);
  } else {
    _XmTextFieldSetSel2(w, position, position, False, event->xbutton.time);
  }
  
  tf->text.sec_extending = True;
  
  if (!CheckTimerScrolling(w, event))
    DoSecondaryExtend(w, event->xmotion.time);
  
  _XmTextFieldDrawInsertionPoint(tf, True);
}



/* ARGSUSED */
static void 
Stuff(Widget w,
      XEvent *event,
      char **params,
      Cardinal *num_params)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  XPoint *point = NULL;

  /* Request targets from the selection owner so you can decide what to
   * request.  The decision process and request for the selection is
   * taken care of in HandleTargets().
   */
  if (event && event->type == ButtonRelease) {
      /* WARNING: do not free the following memory in this module.  It
       * will be freed in FreeLocationData, triggered at the end of
       * the data transfer operation.
       */
      point = (XPoint *) XtMalloc(sizeof(XPoint));
      point->x = event->xbutton.x;
      point->y = event->xbutton.y;
  }
  
  if (tf->text.selection_link)
    XmePrimarySink(w, XmLINK, (XtPointer) point, 
		   event->xbutton.time);
  else if (tf->text.selection_move)
    XmePrimarySink(w, XmMOVE, (XtPointer) point, 
		   event->xbutton.time);
  else
    XmePrimarySink(w, XmCOPY, (XtPointer) point,
		   event->xbutton.time);
}

/* ARGSUSED */
void 
_XmTextFieldHandleSecondaryFinished(Widget w,
			 XEvent *event)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  TextFDestData dest_data;
  XmTextPosition left, right;
  int adjustment = 0;
  Time time = XtLastTimestampProcessed(XtDisplay(w));
  XmAnyCallbackStruct cb;

  dest_data = GetTextFDestData(w);
  
  if (dest_data->has_destination) {
    adjustment = (int) (tf->text.sec_pos_right - tf->text.sec_pos_left);

    doSetHighlight(w, tf->text.sec_pos_left,
			    tf->text.sec_pos_right, XmHIGHLIGHT_NORMAL);
    if (dest_data->position <= tf->text.sec_pos_left) {
      tf->text.sec_pos_left += adjustment - dest_data->replace_length;
      tf->text.sec_pos_right += adjustment - dest_data->replace_length;
    } else if (dest_data->position > tf->text.sec_pos_left &&
	       dest_data->position < tf->text.sec_pos_right) {
      tf->text.sec_pos_left -= dest_data->replace_length;
      tf->text.sec_pos_right += adjustment - dest_data->replace_length;
    }
  }

  left = tf->text.sec_pos_left;
  right = tf->text.sec_pos_right;

  /* This will mark the has_secondary field to False. */
  (void) _XmTextFieldSetSel2(w, 1, 0, False, time);

  if (_XmTextFieldReplaceText(tf, event, left, right, NULL, 0, False /* don't adjust cursor position */)) {
    XmTextPosition cursorPos;
    if (dest_data->has_destination && TextF_CursorPosition(tf) > right) {
      cursorPos = TextF_CursorPosition(tf) - (right - left);
      if (!dest_data->quick_key)
	_XmTextFieldSetCursorPosition(tf, NULL, cursorPos, True, True);
      (void) SetDestination((Widget) tf, cursorPos, False, time);
    }
    if (!dest_data->has_destination) {
      /* make some adjustments necessary -- cursor position may refer to
      ** text which is gone 
      */
      cursorPos = TextF_CursorPosition(tf);
      if (left < cursorPos) 
		cursorPos -= (right - left);
      tf->text.prim_anchor = cursorPos;
      if (tf->text.add_mode) {
	_XmTextFieldDrawInsertionPoint(tf, False);
	tf->text.add_mode = False;
        TextF_CursorPosition(tf) = cursorPos;
	_XmTextFieldDrawInsertionPoint(tf, True);
      }
      else if (cursorPos != TextF_CursorPosition(tf))
	{
		/* if it changed, redraw, carefully using internal routines 
		** to avoid calling _XmSetDestination
		*/
		_XmTextFieldDrawInsertionPoint(tf, False);
        	TextF_CursorPosition(tf) = cursorPos;
		SetCursorPosition(tf, NULL, cursorPos, False, False, True, ForceTrue);
		_XmTextFieldDrawInsertionPoint(tf, True);
	}
    }

    cb.reason = XmCR_VALUE_CHANGED;
    cb.event = event;
    XtCallCallbackList((Widget) tf, TextF_ValueChangedCallback(tf),
		       (XtPointer) &cb);
  }
}


/*
 * Notify the primary selection that the secondary selection
 * wants to insert it's selection data into the primary selection.
 */
   /* REQUEST TARGETS FROM SELECTION RECEIVER; THEN CALL HANDLETARGETS
    * WHICH LOOKS AT THE TARGET LIST AND DETERMINE WHAT TARGET TO PLACE 
    * IN THE PAIR.  IT WILL THEN DO ANY NECESSARY CONVERSIONS BEFORE 
    * TELLING THE RECEIVER WHAT TO REQUEST AS THE SELECTION VALUE.
    * THIS WILL GUARANTEE THE BEST CHANCE AT A SUCCESSFUL EXCHANGE.
    */
/* ARGSUSED */
static void 
SecondaryNotify(Widget w,
		XEvent *event,
		char **params,
		Cardinal *num_params)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  Atom CS_OF_ENCODING = XmeGetEncodingAtom(w);
  TextFDestData dest_data;
  XmTextPosition left = tf->text.prim_pos_left, right = tf->text.prim_pos_right;

  if (tf->text.selection_move == TRUE && tf->text.has_destination &&
      TextF_CursorPosition(tf) >= tf->text.sec_pos_left &&
      TextF_CursorPosition(tf) <= tf->text.sec_pos_right) {
      /* This will mark the has_secondary field to False. */
      (void) _XmTextFieldSetSel2(w, 1, 0, False, event->xbutton.time);
      return;
  }
  
  /*
   * Determine what the reciever supports so you can tell 'em what to
   * request.
   */
  
  dest_data = GetTextFDestData(w);
  
  dest_data->has_destination = tf->text.has_destination;
  dest_data->position = TextF_CursorPosition(tf);
  dest_data->replace_length = 0;
  
  if (*(num_params) == 1) dest_data->quick_key = True;
  else dest_data->quick_key = False;
  
  if (tf->text.has_primary && left != right) {
    if (dest_data->position >= left && dest_data->position <= right)
      dest_data->replace_length = (int) (right - left);
  }
  
  /*
   * Make a request for the primary selection to convert to 
   * type INSERT_SELECTION as per ICCCM.
   */ 
  
  if (tf->text.selection_link)
    XmeSecondaryTransfer(w, CS_OF_ENCODING, XmLINK, event->xbutton.time);
  else if (tf->text.selection_move)
    XmeSecondaryTransfer(w, CS_OF_ENCODING, XmMOVE, event->xbutton.time);
  else
    XmeSecondaryTransfer(w, CS_OF_ENCODING, XmCOPY, event->xbutton.time);
}

   /*
    * LOOKS AT THE TARGET LIST AND DETERMINE WHAT TARGET TO PLACE 
    * IN THE PAIR.  IT WILL THEN DO ANY NECESSARY CONVERSIONS BEFORE 
    * TELLING THE RECEIVER WHAT TO REQUEST AS THE SELECTION VALUE.
    * THIS WILL GUARANTEE THE BEST CHANCE AT A SUCCESSFUL EXCHANGE.
    */

static void
ProcessBDragRelease(Widget w,
		    XEvent *event,
		    String *params,
		    Cardinal *num_params)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  XButtonEvent      *ev = (XButtonEvent *) event;
  XmTextPosition position;
  
  if (tf->text.extending)
    return;

  /* Work around for intrinsic bug.  Remove once bug is fixed. */
  XtUngrabPointer(w, ev->time);
  
  _XmTextFieldDrawInsertionPoint(tf, False);
  if (!tf->text.cancel) XtUngrabKeyboard(w, CurrentTime);
  
  position = GetPosFromX(tf, (Position) event->xbutton.x);
  
  if (tf->text.sel_start) {
    if (tf->text.has_secondary &&
	tf->text.sec_pos_left != tf->text.sec_pos_right) {
      if ((Dimension)ev->x > tf->core.width || ev->x < 0 ||
	  (Dimension)ev->y > tf->core.height || ev->y < 0) {
	  /* This will mark the has_secondary field to False. */
	  _XmTextFieldSetSel2(w, 1, 0, False, event->xkey.time);
      } else {
	  SecondaryNotify(w, event, params, num_params);
      }
    } else if (!tf->text.sec_drag && !tf->text.cancel &&
	       tf->text.sec_pos_left == position) {
      /*
       * Copy contents of primary selection to the stuff position found above.
       */
      Stuff(w, event, params, num_params);
    }
  }
  
  if (tf->text.select_id) {
    XtRemoveTimeOut(tf->text.select_id);
    tf->text.select_id = 0;
  }
  
  tf->text.sec_extending = False;
  
  tf->text.sec_drag = False;
  tf->text.sel_start = False;
  tf->text.cancel = False;
  _XmTextFieldDrawInsertionPoint(tf, True);
}

static void 
ProcessCopy(Widget w,
	    XEvent *event,
	    char **params,
	    Cardinal *num_params)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  
  _XmTextFieldDrawInsertionPoint(tf, False);
  tf->text.selection_move = FALSE;
  tf->text.selection_link = FALSE;
  ProcessBDragRelease(w, event, params, num_params);
  _XmTextFieldDrawInsertionPoint(tf, True);
}

static void 
ProcessLink(Widget w,
	    XEvent *event,
	    char **params,
	    Cardinal *num_params)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  
  _XmTextFieldDrawInsertionPoint(tf, False);
  tf->text.selection_move = FALSE;
  tf->text.selection_link = TRUE;
  ProcessBDragRelease(w, event, params, num_params);
  _XmTextFieldDrawInsertionPoint(tf, True);
}

static void 
ProcessMove(Widget w,
	    XEvent *event,
	    char **params,
	    Cardinal *num_params)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;

  _XmTextFieldDrawInsertionPoint(tf, False);
  tf->text.selection_move = TRUE;
  tf->text.selection_link = FALSE;
  ProcessBDragRelease(w, event, params, num_params);
  _XmTextFieldDrawInsertionPoint(tf, True);
}


/* ARGSUSED */
static void 
DeleteSelection(Widget w,
		XEvent *event,
		char **params,
		Cardinal *num_params)
{
  (void) TextFieldRemove(w, event);
}

/* ARGSUSED */
static void 
ClearSelection(Widget w,
	       XEvent *event,
	       char **params,
	       Cardinal *num_params)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  XmTextPosition left = tf->text.prim_pos_left;
  XmTextPosition right = tf->text.prim_pos_right;
  int num_spaces = 0;
  XmAnyCallbackStruct cb;
  Boolean rep_result = False;
  
  if (left < right)
    num_spaces = (int)(right - left);
  else
    num_spaces = (int)(left - right);
  
  if (num_spaces) {
    _XmTextFieldDrawInsertionPoint(tf, False);
    if (tf->text.max_char_size == 1) {
      char spaces_cache[100];
      Cardinal spaces_size;
      char *spaces;
      int i;
      
      spaces_size = num_spaces + 1;
      
      spaces = (char *)XmStackAlloc(spaces_size, spaces_cache);
      
      for (i = 0; i < num_spaces; i++) spaces[i] = ' ';
      spaces[num_spaces] = 0;
      
      rep_result = _XmTextFieldReplaceText(tf, (XEvent *)event, left, right,
					    spaces, num_spaces, False);
      XmStackFree(spaces, spaces_cache);
    } else {
      wchar_t *wc_spaces;
      int i;
      
      wc_spaces = (wchar_t *)XtMalloc((unsigned)
				      (num_spaces + 1) * sizeof(wchar_t));
      
      for (i = 0; i < num_spaces; i++) {
	(void)mbtowc(&wc_spaces[i], " ", 1);
      }
      
      rep_result = _XmTextFieldReplaceText(tf, (XEvent *)event, left, right,
					    (char*)wc_spaces, num_spaces, 
					    False);
      
      XtFree((char*)wc_spaces);
    }
    if (rep_result) {
      cb.reason = XmCR_VALUE_CHANGED;
      cb.event = event;
      XtCallCallbackList((Widget) tf, TextF_ValueChangedCallback(tf),
			 (XtPointer) &cb);
    }
    _XmTextFieldDrawInsertionPoint(tf, True);
  }
}

/* ARGSUSED */
static void 
PageRight(Widget w,
	  XEvent *event,
	  char **params,
	  Cardinal *num_params)
{
  Position x, y;
  int length = 0, value;
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  Dimension margin_width = TextF_MarginWidth(tf) +
    tf->primitive.shadow_thickness +
      tf->primitive.highlight_thickness;
  
  TextFieldResetIC(w);
  if (tf->text.max_char_size != 1) {
    length = FindPixelLength(tf, (char*)TextF_WcValue(tf),
			     tf->text.string_length);
  } else {
    length = FindPixelLength(tf, TextF_Value(tf), tf->text.string_length);
  }

  /* if widget is wider than text, ignore page-right action*/
  if (length <= (int)(tf->core.width - (2 * margin_width)))
    return;
  
  _XmTextFieldDrawInsertionPoint(tf, False);
  
  if (*num_params > 0)
  {
      /* There is only one valid reptype value for this reptype, i.e.
	 "extend". A True return value means that parameter was "extend". */
      if (_XmConvertActionParamToRepTypeId((Widget) w,
			   XmRID_TEXTFIELD_EXTEND_MOVEMENT_ACTION_PARAMS,
			   params[0], False, &value) == True)
      {
	  SetAnchorBalancing(tf, TextF_CursorPosition(tf));
      }
  }
  
  GetXYFromPos(tf, TextF_CursorPosition(tf), &x, &y);
  
  if ((int)(length - ((int)(tf->core.width - (2 * margin_width)) -
		tf->text.h_offset) ) > (int)(tf->core.width - (2 * margin_width)))
    tf->text.h_offset -= tf->core.width - (2 * margin_width);
  else
    tf->text.h_offset = -(length - (tf->core.width - (2 * margin_width)));
  
  RedisplayText(tf, 0, tf->text.string_length);
  _XmTextFieldSetCursorPosition(tf, event, GetPosFromX(tf, x), 
				True, True);
  
  if (*num_params > 0)
  {
      /* There is only one valid reptype value for this reptype, i.e.
	 "extend". A True return value means that parameter was "extend". */
      if (_XmConvertActionParamToRepTypeId((Widget) w,
			   XmRID_TEXTFIELD_EXTEND_MOVEMENT_ACTION_PARAMS,
			   params[0], False, &value) == True)
      {
	  KeySelection(w, event, params, num_params);
      }
  }
  
  _XmTextFieldDrawInsertionPoint(tf, True);
}

/* ARGSUSED */
static void 
PageLeft(Widget w,
	 XEvent *event,
	 char **params,
	 Cardinal *num_params)
{
  Position x, y;
  int value;
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  int margin_width = (int)TextF_MarginWidth(tf) +
    tf->primitive.shadow_thickness +
      tf->primitive.highlight_thickness;
  
  TextFieldResetIC(w);

  _XmTextFieldDrawInsertionPoint(tf, False);
  
  if (*num_params > 0)
  {
      /* There is only one valid reptype value for this reptype, i.e.
	 "extend". A True return value means that parameter was "extend". */
      if (_XmConvertActionParamToRepTypeId((Widget) w,
			   XmRID_TEXTFIELD_EXTEND_MOVEMENT_ACTION_PARAMS,
			   params[0], False, &value) == True)
      {
	  SetAnchorBalancing(tf, TextF_CursorPosition(tf));
      }
  }
  
  GetXYFromPos(tf, TextF_CursorPosition(tf), &x, &y);
  if (margin_width  <= tf->text.h_offset +
      ((int)tf->core.width - (2 * margin_width)))
    tf->text.h_offset = margin_width;
  else
    tf->text.h_offset += tf->core.width - (2 * margin_width);
  
  RedisplayText(tf, 0, tf->text.string_length);
  _XmTextFieldSetCursorPosition(tf, event, GetPosFromX(tf, x),
				True, True);
  
  if (*num_params > 0)
  {
      /* There is only one valid reptype value for this reptype, i.e.
	 "extend". A True return value means that parameter was "extend". */
      if (_XmConvertActionParamToRepTypeId((Widget) w,
			   XmRID_TEXTFIELD_EXTEND_MOVEMENT_ACTION_PARAMS,
			   params[0], False, &value) == True)
      {
	  KeySelection(w, event, params, num_params);
      }
  }
  
  _XmTextFieldDrawInsertionPoint(tf, True);
}

static void 
CopyPrimary(Widget w,
	    XEvent *event,
	    char **params,
	    Cardinal *num_params)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  
  TextFieldResetIC(w);
  _XmTextFieldDrawInsertionPoint(tf, False);
  tf->text.selection_move = False;
  tf->text.selection_link = False;
  
  /* perform the primary paste action */
  Stuff(w, event, params, num_params);
  _XmTextFieldDrawInsertionPoint(tf, True);
}

static void 
CutPrimary(Widget w,
	   XEvent *event,
	   char **params,
	   Cardinal *num_params)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  
  TextFieldResetIC(w);
  _XmTextFieldDrawInsertionPoint(tf, False);
  tf->text.selection_move = True;
  tf->text.selection_link = False;

  Stuff(w, event, params, num_params);
  _XmTextFieldDrawInsertionPoint(tf, True);
}

static void 
LinkPrimary(Widget w,
	   XEvent *event,
	   char **params,
	   Cardinal *num_params)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  
  _XmTextFieldDrawInsertionPoint(tf, False);
  tf->text.selection_move = False; 
  tf->text.selection_link = True;
  Stuff(w, event, params, num_params);
  _XmTextFieldDrawInsertionPoint(tf, True);
}

/* ARGSUSED */
static void 
SetAnchor(Widget w,
	  XEvent *event,
	  char **params,
	  Cardinal *num_params)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  
  tf->text.prim_anchor = TextF_CursorPosition(tf);
  (void) SetDestination(w, tf->text.prim_anchor, False, event->xkey.time);
  if (tf->text.has_primary) {
    _XmTextFieldStartSelection(tf, tf->text.prim_anchor,
			       tf->text.prim_anchor, event->xkey.time);
    if (tf->text.add_mode) {
      _XmTextFieldDrawInsertionPoint(tf, False);
      tf->text.add_mode = False;
      _XmTextFieldDrawInsertionPoint(tf, True);
    }
  }
}

/* ARGSUSED */
static void 
ToggleOverstrike(Widget w,
		 XEvent *event,
		 char **params,
		 Cardinal *num_params)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  
  TextFieldResetIC(w);
  _XmTextFieldDrawInsertionPoint(tf, False);
  tf->text.overstrike = !tf->text.overstrike;
  tf->text.refresh_ibeam_off = True;
  if (tf->text.overstrike)
    tf->text.cursor_width = tf->text.cursor_height >> 1;
  else {
    tf->text.cursor_width = 5;
    if (tf->text.cursor_height > 19) 
      tf->text.cursor_width++;
  }
  _XmTextFieldDrawInsertionPoint(tf, True);
}

/* ARGSUSED */
static void 
ToggleAddMode(Widget w,
	      XEvent *event,
	      char **params,
	      Cardinal *num_params)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  
  _XmTextFieldDrawInsertionPoint(tf, False);
  
  tf->text.add_mode = !tf->text.add_mode;	
  if (tf->text.add_mode &&
      (!tf->text.has_primary ||
       tf->text.prim_pos_left == tf->text.prim_pos_right))
    tf->text.prim_anchor = TextF_CursorPosition(tf);
  
  _XmTextFieldDrawInsertionPoint(tf, True);
}

/* ARGSUSED */
static void 
SelectAll(Widget w,
	  XEvent *event,
	  char **params,
	  Cardinal *num_params)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  
  TextFieldResetIC(w);
  _XmTextFieldDrawInsertionPoint(tf, False);
  if (tf->text.take_primary)
    _XmTextFieldStartSelection(tf, 0, tf->text.string_length,
			       event->xbutton.time);
  else
    SetSelection(tf, 0, tf->text.string_length, True);
  
  /* Call _XmTextFieldSetCursorPosition to force image gc to be updated
   * in case the i-beam is contained within the selection */
  
  tf->text.pending_off = False;
  
  _XmTextFieldSetCursorPosition(tf, NULL, TextF_CursorPosition(tf),
				False, False);
  tf->text.prim_anchor = 0;
  
  (void) SetDestination(w, TextF_CursorPosition(tf),
			False, event->xkey.time);
  _XmTextFieldDrawInsertionPoint(tf, True);
}

/* ARGSUSED */
static void 
DeselectAll(Widget w,
	    XEvent *event,
	    char **params,
	    Cardinal *num_params)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  
  _XmTextFieldDrawInsertionPoint(tf, False);
  SetSelection(tf, TextF_CursorPosition(tf), TextF_CursorPosition(tf), True);
  tf->text.pending_off = True;
  _XmTextFieldSetCursorPosition(tf, event, TextF_CursorPosition(tf),
				True, True);
  tf->text.prim_anchor = TextF_CursorPosition(tf);
  (void) SetDestination(w, TextF_CursorPosition(tf),
			False, event->xkey.time);
  _XmTextFieldDrawInsertionPoint(tf, True);
}

/* ARGSUSED */
static void 
VoidAction(Widget w,
	   XEvent *event,
	   char **params,
	   Cardinal *num_params)
{
  /* Do Nothing */
}

/* ARGSUSED */
static void 
CutClipboard(Widget w,
	     XEvent *event,
	     char **params,
	     Cardinal *num_params)
{
  XmTextFieldWidget tf = (XmTextFieldWidget)w;

  _XmTextFieldDrawInsertionPoint(tf, False);
  if (TextF_Editable(tf) && tf->text.prim_pos_left != tf->text.prim_pos_right)
    (void) XmeClipboardSource(w, XmMOVE, event->xkey.time);
  _XmTextFieldDrawInsertionPoint(tf, True);
}

/* ARGSUSED */
static void 
CopyClipboard(Widget w,
	      XEvent *event,
	      char **params,
	      Cardinal *num_params)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  
  _XmTextFieldDrawInsertionPoint(tf, False);
  if (tf->text.prim_pos_left != tf->text.prim_pos_right)
    (void) XmeClipboardSource(w, XmCOPY, event->xkey.time);
  (void) SetDestination(w, TextF_CursorPosition(tf), False, event->xkey.time);
  _XmTextFieldDrawInsertionPoint(tf, True);
}

/* ARGSUSED */
static void 
PasteClipboard(Widget w,
	       XEvent *event,
	       char **params,
	       Cardinal *num_params)
{
  _XmTextFieldDrawInsertionPoint((XmTextFieldWidget)w, False);
  ((XmTextFieldWidget)w)->text.selection_move = FALSE;
  ((XmTextFieldWidget)w)->text.selection_link = FALSE;
  XmeClipboardSink(w, XmCOPY, NULL);
  _XmTextFieldDrawInsertionPoint((XmTextFieldWidget)w, True);
}

Boolean
XmTextFieldPaste(Widget w)     
{
  Boolean status;
  _XmWidgetToAppContext(w);

  _XmAppLock(app);
  TextFieldResetIC(w);
  ((XmTextFieldWidget)w)->text.selection_move = FALSE;
  ((XmTextFieldWidget)w)->text.selection_link = FALSE;
  status = XmeClipboardSink(w, XmCOPY, NULL);

  _XmAppUnlock(app);
  return(status);
}

Boolean
XmTextFieldPasteLink(Widget w)     
{
  Boolean status;
  _XmWidgetToAppContext(w);

  _XmAppLock(app);
  ((XmTextFieldWidget)w)->text.selection_move = FALSE;
  ((XmTextFieldWidget)w)->text.selection_link = TRUE;
  status = XmeClipboardSink(w, XmLINK, NULL);

  _XmAppUnlock(app);
  return(status);
}

/* ARGSUSED */
static void 
TraverseDown(Widget w,
	     XEvent *event,
	     char **params,
	     Cardinal *num_params)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  
  if (tf->primitive.navigation_type == XmNONE && VerifyLeave(tf, event)) {
    tf->text.traversed = True;
    if (!_XmMgrTraversal(w, XmTRAVERSE_DOWN))
      tf->text.traversed = False;
  }
}


/* ARGSUSED */
static void 
TraverseUp(Widget w,
	   XEvent *event,
	   char **params,
	   Cardinal *num_params)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  
  if (tf->primitive.navigation_type == XmNONE && VerifyLeave(tf, event)) {
    tf->text.traversed = True;
    if (!_XmMgrTraversal(w, XmTRAVERSE_UP))
      tf->text.traversed = False;
  }
}

/* ARGSUSED */
static void 
TraverseHome(Widget w,
	     XEvent *event,
	     char **params,
	     Cardinal *num_params)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  
  /* Allow the verification routine to control the traversal */
  if (tf->primitive.navigation_type == XmNONE && VerifyLeave(tf, event)) {
    tf->text.traversed = True;
    if (!_XmMgrTraversal(w, XmTRAVERSE_HOME))
      tf->text.traversed = False;
  }
}


/* ARGSUSED */
static void 
TraverseNextTabGroup(Widget w,
		     XEvent *event,
		     char **params,
		     Cardinal *num_params)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  
  /* Allow the verification routine to control the traversal */
  if (VerifyLeave(tf, event)) {
    XmTraversalDirection dir;
    XmDisplay xm_dpy = (XmDisplay) XmGetXmDisplay(XtDisplay(w));
    Boolean enable_button_tab = xm_dpy->display.enable_button_tab;

    dir = (enable_button_tab ?
	   XmTRAVERSE_GLOBALLY_FORWARD : XmTRAVERSE_NEXT_TAB_GROUP);

    tf->text.traversed = True;
    if (!_XmMgrTraversal(w, dir))
      tf->text.traversed = False;
  }
}


/* ARGSUSED */
static void 
TraversePrevTabGroup(Widget w,
		     XEvent *event,
		     char **params,
		     Cardinal *num_params)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  
  /* Allow the verification routine to control the traversal */
  if (VerifyLeave(tf, event)) {
    XmTraversalDirection dir;
    XmDisplay xm_dpy = (XmDisplay) XmGetXmDisplay(XtDisplay(w));
    Boolean enable_button_tab = xm_dpy->display.enable_button_tab;

    dir = (enable_button_tab ? 
	   XmTRAVERSE_GLOBALLY_BACKWARD : XmTRAVERSE_PREV_TAB_GROUP);

    tf->text.traversed = True;
    if (!_XmMgrTraversal(w, dir))
      tf->text.traversed = False;
  }
}


/* ARGSUSED */
static void 
TextEnter(Widget w,
	  XEvent *event,
	  String *params,
	  Cardinal *num_params)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  XmAnyCallbackStruct cb;
  XRectangle xmim_area;
  XPoint xmim_point;
  
  /* Use != NotifyInferior along with event->xcrossing.focus to avoid
   * sending input method info if reason for the event is pointer moving
   * from TextF widget to over-the-spot window (case when over-the-spot
   * is child of TextF widget). */
  if (_XmGetFocusPolicy(w) != XmEXPLICIT && !(tf->text.has_focus) &&
      event->xcrossing.focus &&
      (event->xcrossing.detail != NotifyInferior)) {
    _XmTextFieldDrawInsertionPoint(tf, False);
    tf->text.blink_on = False;
    tf->text.has_focus = True;
    if (XtIsSensitive(w)) ChangeBlinkBehavior(tf, True);
    _XmTextFieldDrawInsertionPoint(tf, True);
    GetXYFromPos(tf, TextF_CursorPosition(tf), &xmim_point.x, 
		 &xmim_point.y);
    (void)TextFieldGetDisplayRect((Widget)tf, &xmim_area);
    XmImVaSetFocusValues(w, XmNspotLocation, &xmim_point, 
			 XmNarea, &xmim_area, NULL);
    cb.reason = XmCR_FOCUS;
    cb.event = event;
    XtCallCallbackList (w, tf->text.focus_callback, (XtPointer) &cb);
  }
  
  _XmPrimitiveEnter(w, event, params, num_params);
}


/* ARGSUSED */
static void 
TextLeave(Widget w,
	  XEvent *event,
	  String *params,
	  Cardinal *num_params)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  
  /* use detail!= NotifyInferior to handle focus change due to pointer
   * wandering into over-the-spot input window - we don't want to change
   * IM's focus state in this case. */
  if (_XmGetFocusPolicy(w) != XmEXPLICIT && tf->text.has_focus &&
      event->xcrossing.focus &&
      (event->xcrossing.detail != NotifyInferior)) {
    if (XtIsSensitive(w)) ChangeBlinkBehavior(tf, False);
    _XmTextFieldDrawInsertionPoint(tf, False);
    tf->text.has_focus = False;
    tf->text.blink_on = True;
    _XmTextFieldDrawInsertionPoint(tf, True);
    (void) VerifyLeave(tf, event);
    XmImUnsetFocus(w);
  }
  
  _XmPrimitiveLeave(w, event, params, num_params);
}

/****************************************************************
 *
 * Private definitions.
 *
 ****************************************************************/

/*
 * ClassPartInitialize sets up the fast subclassing for the widget.i
 * It also merges translation tables.
 */
static void 
ClassPartInitialize(WidgetClass w_class)
{
  char *event_bindings;
  
  _XmFastSubclassInit (w_class, XmTEXT_FIELD_BIT);
  event_bindings = (char *)XtMalloc((unsigned) (strlen(EventBindings1) +
						strlen(EventBindings2) +
						strlen(EventBindings3) + 1));
  
  strcpy(event_bindings, EventBindings1);
  strcat(event_bindings, EventBindings2);
  strcat(event_bindings, EventBindings3);
  w_class->core_class.tm_table = 
    (String) XtParseTranslationTable(event_bindings);
  XtFree(event_bindings);
}

/****************************************************************
 *
 * Private functions used in Initialize.
 *
 ****************************************************************/

/*
 * Verify that the resource settings are valid.  Print a warning
 * message and reset the s if the are invalid.
 */
static void 
Validates(XmTextFieldWidget tf)
{
  XtPointer temp_ptr;
  
  if (TextF_CursorPosition(tf) < 0) {
    XmeWarning ((Widget)tf, MSG1);
    TextF_CursorPosition(tf) = 0;
  }
  
  if (TextF_Columns(tf) <= 0) {
    XmeWarning ((Widget)tf, MSG2);
    TextF_Columns(tf) = 20;
  }
  
  if (TextF_SelectionArray(tf) == NULL) 
    TextF_SelectionArray(tf) = (XmTextScanType *) sarray;
  
  if (TextF_SelectionArrayCount(tf) <= 0) 
    TextF_SelectionArrayCount(tf) = XtNumber(sarray);
  
  /*
   * Fix for HaL DTS 9841 - copy the selectionArray into dedicated memory.
   */
  temp_ptr = (XtPointer)TextF_SelectionArray(tf);
  TextF_SelectionArray(tf) = 
    (XmTextScanType *)XtMalloc(TextF_SelectionArrayCount(tf) * 
			       sizeof(XmTextScanType));
  memcpy((void *)TextF_SelectionArray(tf), (void *)temp_ptr,
	 (TextF_SelectionArrayCount(tf) * sizeof(XmTextScanType)));
  /*
   * End fix for HaL DTS 9841
   */
}

static Boolean 
LoadFontMetrics(XmTextFieldWidget tf)
{
  XmFontContext context;
  XmFontListEntry next_entry;
  XmFontType type_return = XmFONT_IS_FONT;
  XtPointer tmp_font;
  Boolean have_font_struct = False;
  Boolean have_font_set = False;
  XFontSetExtents *fs_extents;
  XFontStruct *font;
  unsigned long charwidth = 0;
  char* font_tag = NULL;
  
  if (!XmFontListInitFontContext(&context, TextF_FontList(tf)))
    XmeWarning ((Widget)tf, MSG3);
  
  do {
    next_entry = XmFontListNextEntry(context);
    if (next_entry
        && (tmp_font = XmFontListEntryGetFont(next_entry, &type_return))) {
      if (type_return == XmFONT_IS_FONTSET) { 
	font_tag = XmFontListEntryGetTag(next_entry);
	if (!have_font_set) { /* this saves the first fontset found, just in
			       * case we don't find a default tag set.
			       */
	  TextF_UseFontSet(tf) = True;
	  TextF_Font(tf) = (XFontStruct *)tmp_font;
	  have_font_struct = True; /* we have a font set, so no need to 
				    * consider future font structs */
	  have_font_set = True;    /* we have a font set. */
	  
	  if (!strcmp(XmFONTLIST_DEFAULT_TAG, font_tag)) {
	    if (font_tag) XtFree(font_tag);
	    break; /* Break out!  We've found the one we want. */
	  }
	} else if (!strcmp(XmFONTLIST_DEFAULT_TAG, font_tag)) {
	  TextF_Font(tf) = (XFontStruct *)tmp_font;
	  have_font_set = True;    /* we have a font set. */
	  if (font_tag) XtFree(font_tag);
	  break; /* Break out!  We've found the one we want. */
	}
	if (font_tag) XtFree(font_tag);
      } else if (!have_font_struct) {/* return_type must be XmFONT_IS_FONT */
	TextF_UseFontSet(tf) = False;
	TextF_Font(tf)=(XFontStruct*)tmp_font; /* save the first font
						* struct in case no font 
						* set is found */
	have_font_struct = True;                     
      }
    }
  } while(next_entry != NULL);
  
  XmFontListFreeFontContext(context);

  if (!have_font_struct && !have_font_set) {
    XmeWarning ((Widget)tf, MSG4);
    return False;
  }
  
  if(TextF_UseFontSet(tf)) {
    fs_extents = XExtentsOfFontSet((XFontSet)TextF_Font(tf));
    charwidth = (unsigned long)fs_extents->max_logical_extent.width;
    /* max_logical_extent.y is number of pixels from origin to top of
     * rectangle (i.e. y is negative) */
    TextF_FontAscent(tf) = -fs_extents->max_logical_extent.y;
    TextF_FontDescent(tf) = fs_extents->max_logical_extent.height +
      fs_extents->max_logical_extent.y;
  } else {
    font = TextF_Font(tf);
    if (!XGetFontProperty(font, XA_QUAD_WIDTH, &charwidth) ||
	charwidth == 0) {
      if (font->per_char && font->min_char_or_byte2 <= '0' &&
	  font->max_char_or_byte2 >= '0')
	charwidth = font->per_char['0' - font->min_char_or_byte2].width;
      else
	charwidth = font->max_bounds.width;
    }  
    TextF_FontAscent(tf) = font->max_bounds.ascent;
    TextF_FontDescent(tf) = font->max_bounds.descent;
  }
  tf->text.average_char_width = (Dimension) charwidth;
  return True;
}


/* ValidateString makes the following assumption:  if MB_CUR_MAX == 1, value
 * is a char*, otherwise value is a wchar_t*.  The Boolean "is_wchar" indicates
 * if value points to char* or wchar_t* data.
 *
 * It is ValidateString's task to verify that "value" contains only printing
 * characters; all others are discarded.  ValidateString then mallocs data
 * to store the value and assignes it to tf->text.value (if MB_CUR_MAX == 1)
 * or to tf->text.wc_value (if MB_CUR_MAX != 1), setting the opposite
 * pointer to NULL.  It is the callers responsibility to free data before
 * calling ValidateString.
 */
static void 
ValidateString(XmTextFieldWidget tf,
	       char *value,
#if NeedWidePrototypes
	       int is_wchar)
#else
               Boolean is_wchar)
#endif /* NeedWidePrototypes */
{
  /* if value is wchar_t *, must count the characters; else use strlen */
  
  int str_len = 0;
  int i, j;
  char stack_cache[400];
  
  if (!is_wchar) {
    char *temp_str, *curr_str, *start_temp;
    
    str_len = strlen(value);
    temp_str = (char*)XmStackAlloc((Cardinal)str_len + 1, stack_cache);
    start_temp = temp_str;
    curr_str = value;
    
    for (i = 0; i < str_len;) {
      if (tf->text.max_char_size == 1) {
	if (PrintableString(tf, curr_str, 1, False)) {
	  *temp_str = *curr_str;
	  temp_str++;
	} else {
	  char *params[1], err_str[5];
	  sprintf(err_str, "\\%o", (unsigned char) *curr_str);
	  params[0] = err_str;
	  _XmWarningMsg ((Widget)tf, "Unsupported char", MSG5, params, 1);
	}
	curr_str++;
	i++;
      } else {
	wchar_t tmp;
	int num_conv;
	num_conv = mbtowc(&tmp, curr_str, tf->text.max_char_size);
	if (num_conv >= 0 && PrintableString(tf, (char*)&tmp, 1, True)) {
	  for (j = 0; j < num_conv; j++) {
	    *temp_str = *curr_str;
	    temp_str++;
	    curr_str++;
	    i++; 
	  }
	} else {
	  char *params[1], *err_str;

	  if (num_conv >= 0) {
	    int i;

	    err_str = XtMalloc((4 * num_conv) + 1);
	    for (i = 0; i < num_conv; i++) {
	      sprintf(err_str + (i * 4), "\\%o", (unsigned char) curr_str[i]);
	    }
	  }
	  else {
	    err_str = XtMalloc(5);
	    sprintf(err_str, "\\%o", (unsigned char) *curr_str);
	    num_conv = 1;
	  }
	  params[0] = err_str;
	  _XmWarningMsg ((Widget)tf, "Unsupported char", MSG5, params, 1);
	  XtFree(err_str);
	  if (num_conv > 0) {	
	      curr_str += num_conv;
	      i += num_conv;
	  }
	  else {
	      curr_str++;
	      i++;
	  }
	}
      }
    }
    *temp_str = '\0';
    
    /* value contains validated string; now stuff it into the proper
     * instance pointer. */
    if (tf->text.max_char_size == 1) {
      tf->text.string_length = strlen(start_temp);
      /* malloc the space for the text value */
      TextF_Value(tf) = 
	(char *) memcpy(XtMalloc((unsigned)(tf->text.string_length + 30)),
			(void *)start_temp, tf->text.string_length + 1);
      tf->text.size_allocd = tf->text.string_length + 30;
      TextF_WcValue(tf) = NULL;
    } else { /* Need wchar_t* data to set as the widget's value */
      /* count number of wchar's */
      str_len = strlen(start_temp);
      tf->text.string_length = str_len;
      
      tf->text.size_allocd = (tf->text.string_length + 30)*sizeof(wchar_t);
      TextF_WcValue(tf) = (wchar_t*)XtMalloc((unsigned)tf->text.size_allocd);
      tf->text.string_length = mbstowcs(TextF_WcValue(tf), start_temp,
					tf->text.string_length + 30);
      if (tf->text.string_length < 0) tf->text.string_length = 0;
      TextF_Value(tf) = NULL;
    }
    XmStackFree(start_temp, stack_cache);
  } else {  /* pointer passed points to wchar_t* data */
    wchar_t *wc_value, *wcs_temp_str, *wcs_start_temp, *wcs_curr_str;
    char scratch[8];
    int new_len = 0;
    int csize = 1;
    
    wc_value = (wchar_t *) value;
    for (str_len = 0, i = 0; *wc_value != (wchar_t)0L; str_len++)
      wc_value++; /* count number of wchars */
    wcs_temp_str=(wchar_t *)XmStackAlloc((Cardinal)
					 ((str_len+1) * sizeof(wchar_t)),
					 stack_cache);
    wcs_start_temp = wcs_temp_str;
    wcs_curr_str = (wchar_t *) value;
    
    for (i = 0; i < str_len; i++, wcs_curr_str++) {
      if (tf->text.max_char_size == 1) {
	csize = wctomb(scratch, *wcs_curr_str);
	if (csize >= 0 && PrintableString(tf, scratch, csize, False)) {
	  *wcs_temp_str = *wcs_curr_str;
	  wcs_temp_str++;
	  new_len++;
	} else {
	  char *params[1];
          char *err_str;
	  if (csize >= 0) {
	      int i;

	      err_str = XtMalloc((4 * csize) + 1);
	      for (i = 0; i < csize; i++) {
                sprintf(err_str + (i * 4), "\\%o", (unsigned char) scratch[i]);
	      }
	  }
	  else {
	      err_str = XtMalloc(1);
	      err_str[0] = '\0';
	  }
          params[0] = err_str;
	  _XmWarningMsg ((Widget)tf, "Unsupported wchar", WC_MSG1, params, 1);
          XtFree(err_str);
	}
      } else {
	if (PrintableString(tf, (char*)wcs_curr_str, 1, True)) {
	  *wcs_temp_str = *wcs_curr_str;
	  wcs_temp_str++;
	  new_len++;
	} else {
	  char *params[1];
          char *err_str;
	  csize = wctomb(scratch, *wcs_curr_str);
	  if (csize >= 0) {
	      int i;

	      err_str = XtMalloc((4 * csize) + 1);
	      for (i = 0; i < csize; i++) {
                sprintf(err_str + (i * 4), "\\%o", (unsigned char) scratch[i]);
	      }
	  }
	  else {
	      err_str = XtMalloc(1);
	      err_str[0] = '\0';
	  }
	  params[0] = err_str;
	  _XmWarningMsg ((Widget)tf, "Unsupported wchar", WC_MSG1, params, 1);
	  XtFree(err_str);
	}
      }
    } 
    str_len = new_len;
    
    *wcs_temp_str = (wchar_t)0L; /* terminate with a wchar_t NULL */
    
    tf->text.string_length = str_len; /* This is *wrong* if MB_CUR_MAX > 2
				       * with no font set... but what can
				       * ya do? Spec says let it dump core. */
    
    tf->text.size_allocd = (str_len + 30) * sizeof(wchar_t);
    if (tf->text.max_char_size == 1) { /* Need to store data as char* */
      int ret_val = 0;
      TextF_Value(tf) = XtMalloc((unsigned)tf->text.size_allocd);
      ret_val = wcstombs(TextF_Value(tf), wcs_start_temp, 
			 tf->text.size_allocd);
      if (ret_val < 0) tf->text.value[0] = '\0';
      TextF_WcValue(tf) = NULL;
    } else { /* Need to store data as wchar_t* */
      TextF_WcValue(tf) = (wchar_t*)memcpy(XtMalloc((unsigned)
						    tf->text.size_allocd),
					   (void*)wcs_start_temp,
					   (1 + str_len) *
					   sizeof(wchar_t));
      TextF_Value(tf) = NULL;
    }
    XmStackFree((char *)wcs_start_temp, stack_cache);
  }
}

/*
 * Initialize the s in the text fields instance record.
 */
static void 
InitializeTextStruct(XmTextFieldWidget tf)
{
  /* Flag used in losing focus verification to indicate that a traversal
   * key was pressed.  Must be initialized to False.
   */
  
  XIMCallback xim_cb[5];        /* on the spot im callbacks */
  Arg args[11];                 /* To set initial values to input method */
  Cardinal n = 0;
  XPoint xmim_point;
  XRectangle xmim_area;
  tf->text.traversed = False;
  
  tf->text.add_mode = False;
  tf->text.has_focus = False;
  tf->text.blink_on = True;
  tf->text.cursor_on = 0;
  tf->text.has_rect = False;
  tf->text.has_primary = False;
  tf->text.take_primary = True;
  tf->text.has_secondary = False;
  tf->text.has_destination = False;
  tf->text.overstrike = False;
  tf->text.selection_move = False;
  tf->text.sel_start = False;
  tf->text.pending_off = True;
  tf->text.fontlist_created = False;
  tf->text.cancel = False;
  tf->text.extending = False;
  tf->text.prim_time = 0;
  tf->text.dest_time = 0;
  tf->text.select_id = 0;
  tf->text.select_pos_x = 0;
  tf->text.sec_extending = False;
  tf->text.sec_drag = False;
  tf->text.changed_visible = False;
  tf->text.refresh_ibeam_off = True;
  tf->text.in_setvalues = False;
  tf->text.do_resize = True;
  tf->text.have_inverted_image_gc = False;
  tf->text.margin_top = TextF_MarginHeight(tf);
  tf->text.margin_bottom = TextF_MarginHeight(tf);
  tf->text.programmatic_highlights = False; 
  /* tf->text.rt_save = False; */
  
  tf->text.max_char_size = MB_CUR_MAX;
 
  /* copy over the font list */
  if (TextF_FontList(tf) == NULL) {
    TextF_FontList(tf) = 
      XmeGetDefaultRenderTable((Widget)tf, (unsigned char) XmTEXT_FONTLIST);
  
    TextF_FontList(tf) = (XmFontList)XmFontListCopy(TextF_FontList(tf));
    (void)LoadFontMetrics(tf);
   } else {
     TextF_FontList(tf) = (XmFontList)XmFontListCopy(TextF_FontList(tf));
     if(!LoadFontMetrics(tf)) {/*if failed use default */
        XmFontListFree(TextF_FontList(tf));
        TextF_FontList(tf) =
          XmeGetDefaultRenderTable((Widget)tf, (unsigned char) XmTEXT_FONTLIST);

        TextF_FontList(tf) = (XmFontList)XmFontListCopy(TextF_FontList(tf));
        (void)LoadFontMetrics(tf);
     }
   }
  
  tf->text.gc = NULL;
  tf->text.image_gc = NULL;
  tf->text.save_gc = NULL;
  tf->text.cursor_gc = NULL;
  
  tf->text.h_offset = (TextF_MarginWidth(tf) +
		       tf->primitive.shadow_thickness +
		       tf->primitive.highlight_thickness);

  /* ValidateString will verify value contents, convert to appropriate
   * storage form (i.e. char* or wchar_t*), place in the appropriate
   * location (text.value or text.wc_value), and null out opposite
   * pointer.  */
  
  if (TextF_WcValue(tf) != NULL) { /* XmNvalueWcs was set - it rules */
    TextF_Value(tf) = NULL;
    ValidateString(tf, (char*)TextF_WcValue(tf), True);
  } else if (TextF_Value(tf) != NULL)
    ValidateString(tf, TextF_Value(tf), False);
  else /* TextF_Value(tf) is null pointer */
    ValidateString(tf, "", False);
  
  if (TextF_CursorPosition(tf) > tf->text.string_length)
    TextF_CursorPosition(tf) = tf->text.string_length;
  
  tf->text.orig_left = tf->text.orig_right = tf->text.prim_pos_left =
    tf->text.prim_pos_right = tf->text.prim_anchor = TextF_CursorPosition(tf);
  
  tf->text.sec_pos_left = tf->text.sec_pos_right =
    tf->text.sec_anchor = TextF_CursorPosition(tf);
  
  tf->text.cursor_height = tf->text.cursor_width = 0;
  tf->text.stipple_tile = _XmGetInsensitiveStippleBitmap((Widget) tf);
  
  tf->text.add_mode_cursor = XmUNSPECIFIED_PIXMAP;
  tf->text.cursor = XmUNSPECIFIED_PIXMAP;
  tf->text.ibeam_off = XmUNSPECIFIED_PIXMAP;
  tf->text.image_clip = XmUNSPECIFIED_PIXMAP;
  
  tf->text.last_time = 0;
  
  tf->text.sarray_index = 0;
  
  /* Initialize highlight elements */
  tf->text.highlight.number = tf->text.highlight.maximum = 1;
  tf->text.highlight.list = 
    (_XmHighlightRec *)XtMalloc((unsigned)sizeof(_XmHighlightRec));
  tf->text.highlight.list[0].position = 0;
  tf->text.highlight.list[0].mode = XmHIGHLIGHT_NORMAL;
  
  tf->text.timer_id = (XtIntervalId)0;
  tf->text.drag_id = (XtIntervalId)0;
  tf->text.transfer_action = NULL;

  XmTextFieldSetEditable((Widget)tf, TextF_Editable(tf));
  
  if (TextF_Editable(tf)) {
    XmImRegister((Widget)tf, (unsigned int) NULL);
    GetXYFromPos(tf, TextF_CursorPosition(tf), &xmim_point.x, &xmim_point.y);
    (void)TextFieldGetDisplayRect((Widget)tf, &xmim_area);
    n = 0;
    XtSetArg(args[n], XmNfontList, TextF_FontList(tf)); n++;
    XtSetArg(args[n], XmNbackground, tf->core.background_pixel); n++;
    XtSetArg(args[n], XmNforeground, tf->primitive.foreground); n++;
    XtSetArg(args[n], XmNbackgroundPixmap,tf->core.background_pixmap);n++;
    XtSetArg(args[n], XmNspotLocation, &xmim_point); n++;
    XtSetArg(args[n], XmNarea, &xmim_area); n++;
    XtSetArg(args[n], XmNlineSpace, 
	     TextF_FontAscent(tf) + TextF_FontDescent(tf)); n++;

    /*
     * On the spot support. Register preedit callbacks during initialize.
     */
    xim_cb[0].client_data = (XPointer)tf;
    xim_cb[0].callback = (XIMProc)PreeditStart;
    xim_cb[1].client_data = (XPointer)tf;
    xim_cb[1].callback = (XIMProc)PreeditDone;
    xim_cb[2].client_data = (XPointer)tf;
    xim_cb[2].callback = (XIMProc)PreeditDraw;
    xim_cb[3].client_data = (XPointer)tf;
    xim_cb[3].callback = (XIMProc)PreeditCaret;
    XtSetArg(args[n], XmNpreeditStartCallback, &xim_cb[0]); n++;
    XtSetArg(args[n], XmNpreeditDoneCallback, &xim_cb[1]); n++;
    XtSetArg(args[n], XmNpreeditDrawCallback, &xim_cb[2]); n++;
    XtSetArg(args[n], XmNpreeditCaretCallback, &xim_cb[3]); n++;

    XmImSetValues((Widget)tf, args, n);
  }

  /*
   * Initialize on the spot data in tf structure
   */
  tf->text.onthespot = (OnTheSpotData)XtMalloc(sizeof(OnTheSpotDataRec));
  tf->text.onthespot->start = tf->text.onthespot->end =
    tf->text.onthespot->cursor = 0;
  tf->text.onthespot->under_preedit = False;
  tf->text.onthespot->under_verify_preedit = False;
  tf->text.onthespot->verify_commit = False;
}

/*
 * Get the graphics context for filling the background, and for drawing
 * and inverting text.  Used a unique pixmap so all text field widgets
 * share common GCs.
 */
static void 
LoadGCs(XmTextFieldWidget tf,
        Pixel background,
        Pixel foreground)
{
  XGCValues values;
  unsigned long valueMask = (GCFunction | GCForeground | GCBackground | 
			     GCGraphicsExposures);
  unsigned long dynamicMask = GCClipMask;
  unsigned long unusedMask = GCClipXOrigin | GCClipYOrigin | GCFont;

  /*
   * Get GC for saving area under the cursor.
   */
  values.function = GXcopy;
  values.foreground = tf->primitive.foreground;
  values.background = tf->core.background_pixel;
  values.graphics_exposures = (Bool) False;
  if (tf->text.save_gc != NULL)
    XtReleaseGC((Widget)tf, tf->text.save_gc);
  tf->text.save_gc = XtAllocateGC((Widget) tf, tf->core.depth, valueMask,
				  &values, dynamicMask, unusedMask);

  /*
   * Get GC for drawing text.
   */
  
  if (!TextF_UseFontSet(tf)) {
    valueMask |= GCFont;
    values.font = TextF_Font(tf)->fid;
  } 
  values.foreground = foreground ^ background;
  values.background = 0;
  values.graphics_exposures = (Bool) True;
  if (tf->text.gc != NULL)
    XtReleaseGC((Widget)tf, tf->text.gc);
  dynamicMask |= GCForeground | GCBackground | GCFillStyle | GCStipple;
  tf->text.gc = XtAllocateGC((Widget) tf, tf->core.depth, valueMask,
			     &values, dynamicMask, 0);
  
  /* Create a temporary GC - change it later in make IBEAM */
  valueMask |= GCStipple | GCFillStyle;
  values.stipple = tf->text.stipple_tile;
  values.fill_style = FillStippled;
  values.graphics_exposures = (Bool) False;
  if (tf->text.image_gc != NULL)
    XtReleaseGC((Widget)tf, tf->text.image_gc);
  dynamicMask |= (GCTileStipXOrigin | GCTileStipYOrigin | GCFunction);
  tf->text.image_gc = XtAllocateGC((Widget) tf, tf->core.depth, valueMask,
				   &values, dynamicMask, 0);
}

static void 
MakeIBeamOffArea(XmTextFieldWidget tf,
#if NeedWidePrototypes
		 int width,
		 int height)
#else
                 Dimension width,
                 Dimension height)
#endif /* NeedWidePrototypes */
{
  Display *dpy = XtDisplay(tf);
  Screen  *screen = XtScreen(tf);
  
  /* Create a pixmap for storing the screen data where the I-Beam will 
   * be painted */
  
  tf->text.ibeam_off = XCreatePixmap(dpy, RootWindowOfScreen(screen), width,
				     height, tf->core.depth);
  tf->text.refresh_ibeam_off = True;
}

static Pixmap 
FindPixmap(
    Screen *screen,
    char *image_name,
    Pixel foreground,
    Pixel background,
    int depth )
{    
    XmAccessColorDataRec acc_color_rec;

    acc_color_rec.foreground = foreground;
    acc_color_rec.background = background;
    acc_color_rec.top_shadow_color = XmUNSPECIFIED_PIXEL;
    acc_color_rec.bottom_shadow_color = XmUNSPECIFIED_PIXEL;
    acc_color_rec.select_color = XmUNSPECIFIED_PIXEL;
    acc_color_rec.highlight_color = XmUNSPECIFIED_PIXEL;
    return  _XmGetColoredPixmap(screen, image_name, 
				&acc_color_rec, depth, True);
}

static void 
MakeIBeamStencil(XmTextFieldWidget tf,
		 int line_width)
{
  Screen *screen = XtScreen(tf);
  char pixmap_name[64];
  XGCValues values;
  unsigned long valueMask;
  
  sprintf(pixmap_name, "_XmText_%d_%d", tf->text.cursor_height, line_width);
  tf->text.cursor = FindPixmap(screen, pixmap_name, 1, 0, 1);
  
  if (tf->text.cursor == XmUNSPECIFIED_PIXMAP) {
    Display *dpy = XtDisplay(tf);
    XSegment segments[3];
    
    /* Create a pixmap for the I-Beam stencil */
    tf->text.cursor = XCreatePixmap(dpy, XtWindow(tf), tf->text.cursor_width,
				    tf->text.cursor_height, 1);
    
    
    /* Fill in the stencil with a solid in preparation
     * to "cut out" the I-Beam
     */
    values.foreground = 0;
    values.line_width = 0;
    values.fill_style = FillSolid;
    values.function = GXcopy;
    valueMask = GCForeground | GCLineWidth | GCFillStyle | GCFunction;
    XChangeGC(dpy, tf->text.cursor_gc, valueMask, &values);

    XFillRectangle(dpy, tf->text.cursor, tf->text.cursor_gc, 0, 0, 
		   tf->text.cursor_width, tf->text.cursor_height);
    
    /* Change the GC for use in "cutting out" the I-Beam shape */
    values.foreground = 1;
    values.line_width = line_width;
    XChangeGC(dpy, tf->text.cursor_gc, GCForeground | GCLineWidth, &values);
    
    /* Draw the segments of the I-Beam */
    /* 1st segment is the top horizontal line of the 'I' */
    segments[0].x1 = 0;
    segments[0].y1 = line_width - 1;
    segments[0].x2 = tf->text.cursor_width;
    segments[0].y2 = line_width - 1;
    
    /* 2nd segment is the bottom horizontal line of the 'I' */
    segments[1].x1 = 0;
    segments[1].y1 = tf->text.cursor_height - 1;
    segments[1].x2 = tf->text.cursor_width;
    segments[1].y2 = tf->text.cursor_height - 1;
    
    /* 3rd segment is the vertical line of the 'I' */
    segments[2].x1 = tf->text.cursor_width >> 1;
    segments[2].y1 = line_width;
    segments[2].x2 = tf->text.cursor_width >> 1;
    segments[2].y2 = tf->text.cursor_height - 1;
    
    /* Draw the segments onto the cursor */
    XDrawSegments(dpy, tf->text.cursor, tf->text.cursor_gc, segments, 3);
    
    /* Install the cursor for pixmap caching */
    (void) _XmCachePixmap(tf->text.cursor, XtScreen(tf), pixmap_name, 1, 0,
			    1, tf->text.cursor_width, tf->text.cursor_height);
  }
  
  /* Get/create the image_gc used to paint the I-Beam */
  
  valueMask = (GCStipple | GCForeground | GCBackground | GCFillStyle);
  if (!tf->text.overstrike) {
    values.foreground = tf->primitive.foreground;
    values.background = tf->core.background_pixel;
  } else 
    values.background = values.foreground = 
      tf->core.background_pixel ^ tf->primitive.foreground;
  values.stipple = tf->text.cursor;
  values.fill_style = FillStippled;
  XChangeGC(XtDisplay(tf), tf->text.image_gc, valueMask, &values);
  
}


/* The IBeam Stencil must have already been created before this routine
 * is called.
 */

static void 
MakeAddModeCursor(XmTextFieldWidget tf,
		  int line_width)
{
  Screen *screen = XtScreen(tf);
  char pixmap_name[64];
  
  sprintf(pixmap_name, "_XmText_AddMode_%d_%d",
	  tf->text.cursor_height, line_width);
  
  tf->text.add_mode_cursor = FindPixmap(screen, pixmap_name, 1, 0, 1);
  
  if (tf->text.add_mode_cursor == XmUNSPECIFIED_PIXMAP) {
    XtGCMask  valueMask;
    XGCValues values;
    Display *dpy = XtDisplay(tf);
    
    tf->text.add_mode_cursor = XCreatePixmap(dpy, XtWindow(tf),
					     tf->text.cursor_width,
					     tf->text.cursor_height, 1);
    
    values.function = GXcopy;
    valueMask = GCFunction;
    XChangeGC(dpy, tf->text.cursor_gc, valueMask, &values);

    XCopyArea(dpy, tf->text.cursor, tf->text.add_mode_cursor, 
	      tf->text.cursor_gc, 0, 0, 
	      tf->text.cursor_width, tf->text.cursor_height, 0, 0);
    
    valueMask = (GCForeground | GCBackground | GCTile | GCFillStyle | 
		 GCFunction | GCTileStipXOrigin);
    
    values.function = GXand;
    values.tile = tf->text.stipple_tile;
    values.fill_style = FillTiled;
    values.ts_x_origin = -1;
    values.foreground = tf->primitive.foreground; 
    values.background = tf->core.background_pixel;
    
    XChangeGC(dpy, tf->text.cursor_gc, valueMask, &values);
    
    XFillRectangle(dpy, tf->text.add_mode_cursor, tf->text.cursor_gc,
		   0, 0, tf->text.cursor_width, tf->text.cursor_height);
    
    /* Install the pixmap for pixmap caching */
    _XmCachePixmap(tf->text.add_mode_cursor,
		     XtScreen(tf), pixmap_name, 1, 0,
		     1, tf->text.cursor_width, tf->text.cursor_height);
  }
}


static void 
MakeCursors(XmTextFieldWidget tf)
{
  Screen *screen = XtScreen(tf);
  int line_width = 1;
  int oldwidth = tf->text.cursor_width;
  int oldheight = tf->text.cursor_height;
   
  if (!XtIsRealized((Widget) tf)) return;
  
  tf->text.cursor_width = 5;
  tf->text.cursor_height = TextF_FontAscent(tf) + TextF_FontDescent(tf);
  
  /* setup parameters to make a thicker I-Beam */
  if (tf->text.cursor_height > 19) {
    tf->text.cursor_width++;
    line_width = 2;
  }
  
  if (tf->text.cursor == XmUNSPECIFIED_PIXMAP ||
      tf->text.add_mode_cursor == XmUNSPECIFIED_PIXMAP ||
      tf->text.ibeam_off == XmUNSPECIFIED_PIXMAP ||
      oldheight != tf->text.cursor_height || 
      oldwidth != tf->text.cursor_width) {

    if (tf->text.cursor_gc == NULL) {
      unsigned long valueMask = 0;
      XGCValues values;
      unsigned long dynamicMask = 
	GCForeground | GCLineWidth | GCTile | GCFillStyle | 
	GCBackground | GCFunction | GCTileStipXOrigin;

      tf->text.cursor_gc = XtAllocateGC((Widget)tf, 1, valueMask, &values,
					dynamicMask, 0);
    }

    /* Remove old ibeam off area */
    if (tf->text.ibeam_off != XmUNSPECIFIED_PIXMAP)
      XFreePixmap(XtDisplay((Widget)tf), tf->text.ibeam_off);
    
    /* Remove old insert cursor */
    if (tf->text.cursor != XmUNSPECIFIED_PIXMAP) {
      (void) XmDestroyPixmap(screen, tf->text.cursor);
      tf->text.cursor = XmUNSPECIFIED_PIXMAP;
    }
    
    /* Remove old add mode cursor */
    if (tf->text.add_mode_cursor != XmUNSPECIFIED_PIXMAP) {
      (void) XmDestroyPixmap(screen, tf->text.add_mode_cursor);
      tf->text.add_mode_cursor = XmUNSPECIFIED_PIXMAP;
    }
    
    /* Create area in which to save text located underneath I beam */
    MakeIBeamOffArea(tf, MAX(tf->text.cursor_height>>1,tf->text.cursor_height),
		     tf->text.cursor_height);
    
    /* Create a new i-beam cursor */
    MakeIBeamStencil(tf, line_width);
    
    /* Create a new add_mode cursor */
    MakeAddModeCursor(tf, line_width);
  }
  
  if (tf->text.overstrike)
    tf->text.cursor_width = tf->text.cursor_height >> 1;
}

/* ARGSUSED */
static void
DragProcCallback(Widget w,
		 XtPointer client,
		 XtPointer call)
{
  enum { XmACOMPOUND_TEXT, XmATEXT, NUM_ATOMS };
  static char *atom_names[] = { XmSCOMPOUND_TEXT, XmSTEXT };

  XmDragProcCallbackStruct *cb = (XmDragProcCallbackStruct *)call;
  Widget drag_cont;
  Atom targets[4];
  Arg args[10];
  Atom *exp_targets;
  Cardinal num_exp_targets, n;
  Atom atoms[XtNumber(atom_names)];
  
  assert(XtNumber(atom_names) == NUM_ATOMS);
  XInternAtoms(XtDisplay(w), atom_names, XtNumber(atom_names), False, atoms);

  targets[0] = XmeGetEncodingAtom(w);
  targets[1] = atoms[XmACOMPOUND_TEXT];
  targets[2] = XA_STRING;
  targets[3] = atoms[XmATEXT];
  
  drag_cont = cb->dragContext;
  
  n = 0;
  XtSetArg(args[n], XmNexportTargets, &exp_targets); n++;
  XtSetArg(args[n], XmNnumExportTargets, &num_exp_targets); n++;
  XtGetValues(drag_cont, args, n);
  
  switch(cb->reason) {
  case XmCR_DROP_SITE_ENTER_MESSAGE:
    if (XmTargetsAreCompatible(XtDisplay(drag_cont), exp_targets,
			       num_exp_targets, targets, 4))
      cb->dropSiteStatus = XmVALID_DROP_SITE;
    else
      cb->dropSiteStatus = XmINVALID_DROP_SITE;
    break;
  case XmCR_DROP_SITE_LEAVE_MESSAGE:
  case XmCR_DROP_SITE_MOTION_MESSAGE:
  case XmCR_OPERATION_CHANGED:
    break;
  default:
    /* other messages we consider invalid */
    cb->dropSiteStatus = XmINVALID_DROP_SITE;
    break;
  }

  if (cb -> dropSiteStatus == XmVALID_DROP_SITE) {
    if (cb -> operation != XmDROP_COPY &&
	cb -> operation != XmDROP_MOVE)
      cb -> dropSiteStatus = XmINVALID_DROP_SITE;
  }
}

static void
RegisterDropSite(Widget w)
{
  enum { XmACOMPOUND_TEXT, XmATEXT, NUM_ATOMS };
  static char *atom_names[] = { XmSCOMPOUND_TEXT, XmSTEXT };

  Atom targets[4];
  Arg args[10];
  int n;
  Atom atoms[XtNumber(atom_names)];
  
  assert(XtNumber(atom_names) == NUM_ATOMS);
  XInternAtoms(XtDisplay(w), atom_names, XtNumber(atom_names), False, atoms);

  targets[0] = XmeGetEncodingAtom(w);
  targets[1] = atoms[XmACOMPOUND_TEXT];
  targets[2] = XA_STRING;
  targets[3] = atoms[XmATEXT];
  
  n = 0;
  XtSetArg(args[n], XmNimportTargets, targets); n++;
  XtSetArg(args[n], XmNnumImportTargets, 4); n++;
  XtSetArg(args[n], XmNdragProc, DragProcCallback); n++;
  XmeDropSink(w, args, n);
}

/*
 * Initialize
 *    Intializes the text data and ensures that the data in new
 * is valid.
 */

/* ARGSUSED */
static void 
Initialize(Widget request,
	   Widget new_w,
	   ArgList args,
	   Cardinal *num_args)
{
  XmTextFieldWidget req_tf = (XmTextFieldWidget) request;
  XmTextFieldWidget new_tf = (XmTextFieldWidget) new_w;
  Dimension width, height;
  
  Validates(new_tf);
  
  InitializeTextStruct(new_tf);
  
  LoadGCs(new_tf, new_tf->core.background_pixel,
	  new_tf->primitive.foreground);
  
  ComputeSize(new_tf, &width, &height);
  
  if (req_tf->core.width == 0)
    new_tf->core.width = width;
  if (req_tf->core.height == 0)
    new_tf->core.height = height;
  
  RegisterDropSite(new_w);
  
  if (new_tf->text.verify_bell == (Boolean) XmDYNAMIC_BOOL) {
    if (_XmGetAudibleWarning(new_w) == XmBELL) 
      new_tf->text.verify_bell = True;
    else
      new_tf->text.verify_bell = False;
  }
}

static void 
Realize(Widget w,
        XtValueMask *valueMask,
        XSetWindowAttributes *attributes)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  Arg args[11];                 /* To set initial values to input method */
  XIMCallback xim_cb[5];        /* on the spot im callback data */
  Cardinal n = 0;
  
  XtCreateWindow(w, (unsigned int) InputOutput,
		 (Visual *) CopyFromParent, *valueMask, attributes);
  MakeCursors(tf);

  if (TextF_Editable(tf)){
  /*
   * On the spot support. Register preedit callbacks.
   */
    xim_cb[0].client_data = (XPointer)tf;
    xim_cb[0].callback = (XIMProc)PreeditStart;
    xim_cb[1].client_data = (XPointer)tf;
    xim_cb[1].callback = (XIMProc)PreeditDone;
    xim_cb[2].client_data = (XPointer)tf;
    xim_cb[2].callback = (XIMProc)PreeditDraw;
    xim_cb[3].client_data = (XPointer)tf;
    xim_cb[3].callback = (XIMProc)PreeditCaret;
    XtSetArg(args[n], XmNpreeditStartCallback, &xim_cb[0]); n++;
    XtSetArg(args[n], XmNpreeditDoneCallback, &xim_cb[1]); n++;
    XtSetArg(args[n], XmNpreeditDrawCallback, &xim_cb[2]); n++;
    XtSetArg(args[n], XmNpreeditCaretCallback, &xim_cb[3]); n++;
    XmImSetValues((Widget)tf, args, n);
  }
}

static void 
Destroy(Widget wid)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) wid;
  Widget dest = XmGetDestination(XtDisplay(wid));
  
  if (dest == wid)
    _XmSetDestination(XtDisplay(wid), NULL); 
  
  if (tf->text.timer_id)
    XtRemoveTimeOut(tf->text.timer_id);

  if (tf->text.drag_id)
    XtRemoveTimeOut(tf->text.drag_id);

  if (tf->text.select_id)
    {
    XtRemoveTimeOut(tf->text.select_id);
    tf->text.select_id = 0;
    }
  
  if (tf->text.transfer_action) {
    XtFree((char *)tf->text.transfer_action->event);
    XtFree((char *)tf->text.transfer_action);
  }

  if (tf->text.max_char_size == 1)
    XtFree(TextF_Value(tf));
  else
    XtFree((char *)TextF_WcValue(tf));
  
  XtReleaseGC(wid, tf->text.gc);
  XtReleaseGC(wid, tf->text.image_gc);
  XtReleaseGC(wid, tf->text.save_gc);
  XtReleaseGC(wid, tf->text.cursor_gc);
  
  XtFree((char *)tf->text.highlight.list);
  
  XmFontListFree((XmFontList)TextF_FontList(tf));
  
  if (tf->text.add_mode_cursor != XmUNSPECIFIED_PIXMAP)
    (void) XmDestroyPixmap(XtScreen(tf), tf->text.add_mode_cursor);
  
  if (tf->text.cursor != XmUNSPECIFIED_PIXMAP)
    (void) XmDestroyPixmap(XtScreen(tf), tf->text.cursor);
  
  if (tf->text.ibeam_off != XmUNSPECIFIED_PIXMAP)
    XFreePixmap(XtDisplay((Widget)tf), tf->text.ibeam_off);
  
  if (tf->text.onthespot != NULL)
    XtFree((char *)tf->text.onthespot);

  /*
   * Fix for HaL DTS 9841 - release the data for the selectionArray.
   */
  XtFree((char *)TextF_SelectionArray(tf));
  
  XmImUnregister(wid);
}

static void 
Resize(Widget w)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  int text_width, new_width, offset;

  tf->text.do_resize = False;

#ifdef AS_TEXTFIELD  
  tf->text.h_offset = TextF_MarginWidth(tf) + tf->primitive.shadow_thickness +
    tf->primitive.highlight_thickness;
#else
  new_width = tf->core.width - (2 * (TextF_MarginWidth(tf) + 
				     tf->primitive.shadow_thickness + 
				     tf->primitive.highlight_thickness));
  offset = tf->text.h_offset - (TextF_MarginWidth(tf) + 
				tf->primitive.shadow_thickness + 
				tf->primitive.highlight_thickness);
  if (tf->text.max_char_size != 1) 
    text_width = FindPixelLength(tf, (char *)TextF_WcValue(tf),
				 tf->text.string_length);
  else
    text_width = FindPixelLength(tf, TextF_Value(tf), tf->text.string_length);

  if (text_width - new_width < -offset)
    if (text_width - new_width >= 0)
      tf->text.h_offset = (new_width - text_width) + TextF_MarginWidth(tf) + 
	tf->primitive.shadow_thickness +
	tf->primitive.highlight_thickness;
    else
      tf->text.h_offset = TextF_MarginWidth(tf) + 
	tf->primitive.shadow_thickness +
	tf->primitive.highlight_thickness;

#endif
  
  tf->text.refresh_ibeam_off = True;
  
  (void) AdjustText(tf, TextF_CursorPosition(tf), True);
  
  tf->text.do_resize = True;
}
 

/************************************************************************
 *
 *  QueryGeometry
 *
 ************************************************************************/
static XtGeometryResult 
QueryGeometry(Widget widget,
	      XtWidgetGeometry *intended,
	      XtWidgetGeometry *desired)
{
  /* this function deals with resizeWidth False */
  ComputeSize((XmTextFieldWidget) widget, 
	      &desired->width, &desired->height);
  
  return XmeReplyToQueryGeometry(widget, intended, desired);
}


/*
 * Redisplay will redraw shadows, borders, and text.
 */
/* ARGSUSED */
static void 
TextFieldExpose(Widget w,
		XEvent *event,
		Region region)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  XGCValues values;
  
  
  if (event->xany.type != Expose) return;
  
  tf->text.do_resize = False;
  
  /* I can get here even though the widget isn't visible (i.e. my parent is
   * sized so that I have nothing visible.  In this case, capturing the putback
   * area yields garbage...  And if this area is not in an area where text
   * will be drawn (i.e. forcing something new/valid to be there next time I
   * go to capture it) the garbage persists.  To prevent this, initialize the
   * putback area and then update it to a solid background color.
   */
  
  tf->text.refresh_ibeam_off = False;
  values.clip_mask = None;
  values.foreground = tf->core.background_pixel;
  XChangeGC(XtDisplay(w), tf->text.save_gc, GCForeground|GCClipMask, &values);
  XFillRectangle(XtDisplay(w), tf->text.ibeam_off, tf->text.save_gc, 0, 0,
		 tf->text.cursor_width, tf->text.cursor_height);
  values.foreground = tf->primitive.foreground;
  XChangeGC(XtDisplay(w), tf->text.save_gc, GCForeground, &values);
  
  _XmTextFieldDrawInsertionPoint(tf, False);
  
  if (XtIsRealized((Widget)tf)) {
    if (tf->primitive.shadow_thickness > 0)
      XmeDrawShadows(XtDisplay(tf), XtWindow(tf),
		     tf->primitive.bottom_shadow_GC, 
		     tf->primitive.top_shadow_GC,
		     (int) tf->primitive.highlight_thickness,
		     (int) tf->primitive.highlight_thickness,
		     (int) (tf->core.width - 
			    (2 * tf->primitive.highlight_thickness)),
		     (int) (tf->core.height - 
			    (2 * tf->primitive.highlight_thickness)),
		     (int) tf->primitive.shadow_thickness,
		     XmSHADOW_OUT);
    
    
    if (tf->primitive.highlighted) {
      if (((XmTextFieldWidgetClass)XtClass(tf))
	  ->primitive_class.border_highlight) {
	(*((XmTextFieldWidgetClass) XtClass(tf))
	 ->primitive_class.border_highlight)((Widget) tf);
      } 
    } else {
      if (((XmTextFieldWidgetClass) XtClass(tf))
	  ->primitive_class.border_unhighlight) {
	(*((XmTextFieldWidgetClass) XtClass(tf))
	 ->primitive_class.border_unhighlight)((Widget) tf);
      } 
    } 
    
    RedisplayText(tf, 0, tf->text.string_length);
  }
  
  tf->text.refresh_ibeam_off = True;
  
  _XmTextFieldDrawInsertionPoint(tf, True);
  
  tf->text.do_resize = True;
}

/*
 *
 * SetValues
 *    Checks the new text data and ensures that the data is valid.
 * Invalid values will be rejected and changed back to the old
 * values.
 *
 */
/* ARGSUSED */
static Boolean 
SetValues(Widget old,
	  Widget request,
	  Widget new_w,
	  ArgList args,
	  Cardinal *num_args)
{
  XmTextFieldWidget new_tf = (XmTextFieldWidget) new_w;
  XmTextFieldWidget old_tf = (XmTextFieldWidget) old;
  Boolean cursor_pos_set = False;
  Boolean new_size = False;
  Boolean redisplay = False;
  Boolean redisplay_text = False;
  Boolean new_font = False;
  Boolean mod_ver_ret = False;
  Boolean diff_values = False;
  Dimension new_width = new_tf->core.width;
  Dimension new_height = new_tf->core.height;
  Arg im_args[10];
  XPoint xmim_point;
  XRectangle xmim_area;
  XmTextPosition new_position = 0;
  XmTextPosition newInsert;
  int n = 0;
  
  if (new_w->core.being_destroyed) return False;
  TextFieldResetIC(old);
  
  new_tf->text.in_setvalues = True;
  new_tf->text.redisplay = False;
  
  /* If new cursor position, copy the old cursor pos to the new widget
   * so that when we turn off the i-beam, the current location (old
   * widget) is used, but the new i-beam parameters (on/off, state, ...)
   * are utilized.  Then move the cursor.  Otherwise, just turn off
   * the i-beam. */
  
  if (TextF_CursorPosition(new_tf) != TextF_CursorPosition(old_tf)) {
    new_position = TextF_CursorPosition(new_tf);
    TextF_CursorPosition(new_tf) = TextF_CursorPosition(old_tf);
    _XmTextFieldDrawInsertionPoint(old_tf, False);
    new_tf->text.blink_on = old_tf->text.blink_on;
    new_tf->text.cursor_on = old_tf->text.cursor_on;
    _XmTextFieldSetCursorPosition(new_tf, NULL, new_position,
				  True, True);
    (void) SetDestination(new_w, TextF_CursorPosition(new_tf), False,
			  XtLastTimestampProcessed(XtDisplay(new_w)));
    cursor_pos_set = True;
  } else {
    int ix;
    
    for (ix = 0; ix < *num_args; ix++)
      if (strcmp(args[ix].name, XmNcursorPosition) == 0) {
	cursor_pos_set = True;
	new_position = TextF_CursorPosition(new_tf);
	break;
      }
    
    _XmTextFieldDrawInsertionPoint(old_tf, False);
    new_tf->text.blink_on = old_tf->text.blink_on;
    new_tf->text.cursor_on = old_tf->text.cursor_on;
  }
  
  if (!XtIsSensitive(new_w) &&
      new_tf->text.has_destination) {
    (void) SetDestination(new_w, TextF_CursorPosition(new_tf),
			  True, XtLastTimestampProcessed(XtDisplay(new_w)));
  }
  
  if (TextF_SelectionArray(new_tf) == NULL) 
    TextF_SelectionArray(new_tf) = TextF_SelectionArray(old_tf);
  
  if (TextF_SelectionArrayCount(new_tf) <= 0) 
    TextF_SelectionArrayCount(new_tf) = TextF_SelectionArrayCount(old_tf);
  
  /*
   * Fix for HaL DTS 9841 - If the new and old selectionArrays do not match,
   *			  free the old array and then copy the new array.
   */
  if (TextF_SelectionArray(new_tf) != TextF_SelectionArray(old_tf)) {
    XtPointer temp_ptr;
    
    XtFree((char *)TextF_SelectionArray(old_tf));
    temp_ptr = (XtPointer)TextF_SelectionArray(new_tf);
    TextF_SelectionArray(new_tf) = 
      (XmTextScanType *)XtMalloc(TextF_SelectionArrayCount(new_tf) * 
				 sizeof(XmTextScanType));
    memcpy((void *)TextF_SelectionArray(new_tf), (void *)temp_ptr,
	   (TextF_SelectionArrayCount(new_tf) * sizeof(XmTextScanType)));
  }
  /*
   * End fix for HaL DTS 9841
   */
  
  
  /* Make sure the new_tf cursor position is a valid value.
   */
  if (TextF_CursorPosition(new_tf) < 0) {
    XmeWarning (new_w, MSG1);
    TextF_CursorPosition(new_tf) = TextF_CursorPosition(old_tf);
    cursor_pos_set = False;
  }
  
  if (TextF_FontList(new_tf)!= TextF_FontList(old_tf)) {
    new_font = True;
    if (TextF_FontList(new_tf) == NULL)
      TextF_FontList(new_tf) = 
	XmeGetDefaultRenderTable(new_w, XmTEXT_FONTLIST);
    TextF_FontList(new_tf) =
      (XmFontList)XmFontListCopy(TextF_FontList(new_tf));
    if (!LoadFontMetrics(new_tf)) { /* Fails if font set required but not
                                   * available. */
      XmFontListFree((XmFontList)TextF_FontList(new_tf));
      TextF_FontList(new_tf) = TextF_FontList(old_tf);
      (void)LoadFontMetrics(new_tf); /* it *was* correct, so re-use it */
      new_font = False;
    } else {
      XtSetArg(im_args[n], XmNfontList, TextF_FontList(new_tf)); n++;
      redisplay = True;
    }
  }
  
  /* Four cases to handle for value:
   *   1. user set both XmNvalue and XmNwcValue.
   *   2. user set the opposite resource (i.e. value is a char*
   *      and user set XmNwcValue, or vice versa).
   *   3. user set the corresponding resource (i.e. value is a char*
   *      and user set XmNValue, or vice versa).
   *   4. user set neither XmNValue nor XmNwcValue
   */
  
  /* OSF says:  if XmNvalueWcs set, it overrides all else */
  
  if (new_tf->text.max_char_size == 1) {  
    /* wc_value on new will be NULL unless XmNvalueWcs was set.   */
    if (TextF_WcValue(new_tf) != NULL) { /* must be new if MB_CUR... == 1 */
      ValidateString(new_tf, (char*) TextF_WcValue(new_tf), True);
      diff_values = True;
    } else if (TextF_Value(new_tf) != TextF_Value(old_tf)) {
      diff_values = True;
      if (TextF_Value(new_tf) == NULL) {
	ValidateString(new_tf, "", False);
      } else
	ValidateString(new_tf, TextF_Value(new_tf), False);
    } /* else, no change so don't do anything */
  } else {
    if (TextF_WcValue(new_tf) != TextF_WcValue(old_tf)) {
      diff_values = True;
      if (TextF_WcValue(new_tf) == NULL) {
	TextF_WcValue(new_tf) = (wchar_t*) XtMalloc(sizeof(wchar_t));
	*TextF_WcValue(new_tf) = (wchar_t)NULL;
      }
      ValidateString(new_tf, (char*)TextF_WcValue(new_tf), True);
    } else if (TextF_Value(new_tf) != TextF_Value(old_tf)) {
      /* Someone set XmNvalue */
      diff_values = True;
      if (TextF_Value(new_tf) == NULL)
	ValidateString(new_tf, "", True);
      else
	ValidateString(new_tf, TextF_Value(new_tf), False);
      
    } /* else, no change so don't do anything */
  }
  
  if (diff_values) { /* old value != new value */
    Boolean do_it = True;
    /* If there are modify verify callbacks, verify that we want to continue
     * the action.
     */
    if (TextF_ModifyVerifyCallback(new_tf) || 
	TextF_ModifyVerifyCallbackWcs(new_tf)) {
      /* If the function ModifyVerify() returns false then don't
       * continue with the action.
       */
      char *temp, *old;
      int free_insert;
      XmTextPosition fromPos = 0, toPos;
      int ret_val = 0;

      toPos = old_tf->text.string_length;
      if (new_tf->text.max_char_size == 1) {
	temp = TextF_Value(new_tf);
	mod_ver_ret = ModifyVerify(new_tf, NULL, &fromPos, &toPos,
				   &temp, &new_tf->text.string_length,
				   &newInsert, &free_insert);
      } else {
	old = temp = XtMalloc((unsigned)((new_tf->text.string_length + 1) *
					 new_tf->text.max_char_size));
	ret_val = wcstombs(temp, TextF_WcValue(new_tf), 
			   (new_tf->text.string_length + 1) * 
			   new_tf->text.max_char_size);
	if (ret_val < 0) temp[0] = '\0';
	mod_ver_ret = ModifyVerify(new_tf, NULL, &fromPos, &toPos, &temp,
				   &new_tf->text.string_length, &newInsert,
				   &free_insert);
	if (old != temp) XtFree (old);
      }
      if (free_insert) XtFree(temp);
      if (!mod_ver_ret) {
	if (new_tf->text.verify_bell) XBell(XtDisplay(new_w), 0);
	if (new_tf->text.max_char_size == 1) {
	  TextF_Value(new_tf) = 
	    (char *) memcpy(XtRealloc(TextF_Value(new_tf),
				      (unsigned)old_tf->text.size_allocd),
			    (void*)TextF_Value(old_tf),
			    old_tf->text.string_length + 1);
	  new_tf->text.string_length = old_tf->text.string_length;
	  new_tf->text.size_allocd = old_tf->text.size_allocd;
	  XtFree(TextF_Value(old_tf));
	} else {
	  /* realloc to old size, cast to wchar_t*, and copy the data */
	  TextF_WcValue(new_tf) = 
	    (wchar_t*)memcpy( XtRealloc((char *)TextF_WcValue(new_tf),
					(unsigned)old_tf->text.size_allocd),
			     (void*)TextF_WcValue(old_tf),
			     (size_t) old_tf->text.size_allocd);
	  
	  new_tf->text.string_length = old_tf->text.string_length;
	  new_tf->text.size_allocd = old_tf->text.size_allocd;
	  XtFree((char *)TextF_WcValue(old_tf));
	}
	do_it = False;
      }
    }
    
    if (do_it) {
      XmAnyCallbackStruct cb;
      
      if (new_tf->text.max_char_size == 1)
	XtFree(TextF_Value(old_tf));
      else
	XtFree((char *)TextF_WcValue(old_tf));
      
      doSetHighlight(new_w, new_tf->text.prim_pos_left,
			      new_tf->text.prim_pos_right,
			      XmHIGHLIGHT_NORMAL);
      
      new_tf->text.pending_off = True;    
      
      /* if new_position was > old_tf->text.string_length, last time
       * the SetCursorPosition didn't take.
       */
      if (!cursor_pos_set || new_position > old_tf->text.string_length) {
	_XmTextFieldSetCursorPosition(new_tf, NULL, new_position,
				      True, False);
	if (new_tf->text.has_destination)
	  (void) SetDestination(new_w, TextF_CursorPosition(new_tf), False,
				XtLastTimestampProcessed(XtDisplay(new_w)));
      }
      
      if (TextF_ResizeWidth(new_tf) && new_tf->text.do_resize)
	AdjustSize(new_tf);
      else {
	new_tf->text.h_offset = TextF_MarginWidth(new_tf) + 
	  new_tf->primitive.shadow_thickness +
	    new_tf->primitive.highlight_thickness;
	if (!AdjustText(new_tf, TextF_CursorPosition(new_tf), False))
	  redisplay_text = True;
      }
      
      cb.reason = XmCR_VALUE_CHANGED;
      cb.event = NULL;
      XtCallCallbackList(new_w, TextF_ValueChangedCallback(new_tf),
			 (XtPointer) &cb);
      
    }
  }
  
  if (new_tf->primitive.foreground != old_tf->primitive.foreground ||
      TextF_FontList(new_tf)!= TextF_FontList(old_tf) ||
      new_tf->core.background_pixel != old_tf->core.background_pixel) {
    LoadGCs(new_tf, new_tf->primitive.foreground,
	    new_tf->core.background_pixel);
    MakeCursors(new_tf);
    redisplay = True;
    XtSetArg(im_args[n], XmNbackground, new_tf->core.background_pixel); n++;
    XtSetArg(im_args[n], XmNforeground, new_tf->primitive.foreground); n++;
  }
  
  if (new_tf->text.has_focus && XtIsSensitive((Widget)new_tf) &&
      TextF_BlinkRate(new_tf) != TextF_BlinkRate(old_tf)) {
    
    if (TextF_BlinkRate(new_tf) == 0) {
      new_tf->text.blink_on = True;
      if (new_tf->text.timer_id) {
	XtRemoveTimeOut(new_tf->text.timer_id);
	new_tf->text.timer_id = (XtIntervalId)0;
      }
    } else if (new_tf->text.timer_id == (XtIntervalId)0) {
      new_tf->text.timer_id =
	XtAppAddTimeOut(XtWidgetToApplicationContext(new_w),
			(unsigned long)TextF_BlinkRate(new_tf),
			HandleTimer,
			(XtPointer) new_tf);
    }
    BlinkInsertionPoint(new_tf);
  }
  
  if (TextF_MarginHeight(new_tf) != TextF_MarginHeight(old_tf)) {
    new_tf->text.margin_top = TextF_MarginHeight(new_tf);
    new_tf->text.margin_bottom = TextF_MarginHeight(new_tf);
  }
  
  new_size = TextF_MarginWidth(new_tf) != TextF_MarginWidth(old_tf) ||
             TextF_MarginHeight(new_tf) != TextF_MarginHeight(old_tf) ||
	     TextF_FontList(new_tf) != TextF_FontList(old_tf) ||
	     new_tf->primitive.highlight_thickness !=
	       old_tf->primitive.highlight_thickness ||
	     new_tf->primitive.shadow_thickness !=
	       old_tf->primitive.shadow_thickness;
  
  
  if (TextF_Columns(new_tf) < 0) {
    XmeWarning (new_w, MSG7);
    TextF_Columns(new_tf) = TextF_Columns(old_tf);
  }
  
  if (!(new_width != old_tf->core.width &&
	new_height != old_tf->core.height)) {
    if (TextF_Columns(new_tf) != TextF_Columns(old_tf) || new_size) {
      Dimension width, height;
      
      ComputeSize(new_tf, &width, &height);
      AdjustText(new_tf, 0, False);
      
      if (new_width == old_tf->core.width)
	new_w->core.width = width;
      if (new_height == old_tf->core.height)
	new_w->core.height = height;
      new_tf->text.h_offset = TextF_MarginWidth(new_tf) +
	new_tf->primitive.shadow_thickness +
	  new_tf->primitive.highlight_thickness;
      redisplay = True;
    }
  } else {
    if (new_width != new_tf->core.width)
      new_tf->core.width = new_width;
    if (new_height != new_tf->core.height)
      new_tf->core.height = new_height;
  }
  
  new_tf->text.refresh_ibeam_off = True; /* force update of putback area */
  
  _XmTextFieldDrawInsertionPoint(new_tf, True);
  
  if (XtIsSensitive((Widget)new_tf) != XtIsSensitive((Widget)old_tf)) {
    if (XtIsSensitive(new_w)) {
      _XmTextFieldDrawInsertionPoint(new_tf, False);
      new_tf->text.blink_on = False;
      _XmTextFieldDrawInsertionPoint(new_tf, True);
    } else {
      if (new_tf->text.has_focus) {
	ChangeBlinkBehavior(new_tf, False);
	_XmTextFieldDrawInsertionPoint(new_tf, False);
	new_tf->text.has_focus = False;
	new_tf->text.blink_on = True;
	_XmTextFieldDrawInsertionPoint(new_tf, True);
	(void) VerifyLeave(new_tf, NULL);
      }
    }
    if (new_tf->text.string_length > 0) redisplay = True;
  }
  
  (void)TextFieldGetDisplayRect((Widget)new_tf, &xmim_area);
  GetXYFromPos(new_tf, TextF_CursorPosition(new_tf), &xmim_point.x, 
	       &xmim_point.y);
  
  if (TextF_Editable(old_tf) != TextF_Editable(new_tf)) {
    Boolean editable = TextF_Editable(new_tf);
    TextF_Editable(new_tf) = TextF_Editable(old_tf);
    XmTextFieldSetEditable(new_w, editable);
  } else if (new_font && TextF_Editable(new_tf)) {
    /* We want to be able to connect to an IM if XmNfontList has changed. */
    TextF_Editable(new_tf) = False;
    XmTextFieldSetEditable(new_w, True);
  }
  
  XtSetArg(im_args[n], XmNbackgroundPixmap,
	   new_tf->core.background_pixmap); n++;
  XtSetArg(im_args[n], XmNspotLocation, &xmim_point); n++;
  XtSetArg(im_args[n], XmNarea, &xmim_area); n++;
  XtSetArg(im_args[n], XmNlineSpace, 
	   TextF_FontAscent(new_tf) + TextF_FontDescent(new_tf)); n++;
  XmImSetValues((Widget)new_tf, im_args, n);
  
  if (new_font) XmFontListFree((XmFontList)TextF_FontList(old_tf));
  
  if (!redisplay) redisplay = new_tf->text.redisplay;
  
  /* If I'm forced to redisplay, then actual widget won't be updated
   * until the expose proc.  Force the ibeam putback to be refreshed
   * at expose time so that it reflects true visual state of the
   * widget.  */
  
  if (redisplay) new_tf->text.refresh_ibeam_off = True;
  
  new_tf->text.in_setvalues = False;
  
  if ((!TextF_Editable(new_tf) || !XtIsSensitive(new_w)) &&
      new_tf->text.has_destination)
    (void) SetDestination(new_w, 0, False, (Time)0);
  
  /* don't shrink to nothing */
  if (new_tf->core.width == 0) new_tf->core.width = old_tf->core.width;
  if (new_tf->core.height == 0) new_tf->core.height = old_tf->core.height;
  
  if (!redisplay && redisplay_text) 
    RedisplayText(new_tf, 0, new_tf->text.string_length);
  
  return redisplay;
}

/********************************************
 * AccessTextual trait method implementation 
 ********************************************/

static XtPointer
TextFieldGetValue(Widget w, int format) 
{
  char *str;
  XmString tmp;

  switch(format) {
  case XmFORMAT_XmSTRING:
    str = XmTextFieldGetString(w);
    tmp = XmStringCreateLocalized(str);
    if (str != NULL) XtFree(str);
    return((XtPointer) tmp);
  case XmFORMAT_MBYTE:
    return((XtPointer) XmTextFieldGetString(w));
  case XmFORMAT_WCS:
    return((XtPointer) XmTextFieldGetStringWcs(w));
  }

  return(NULL);
}

static void 
TextFieldSetValue(Widget w, XtPointer s, int format)
{
  char *str;

  switch(format) {
  case XmFORMAT_XmSTRING:
    str = _XmStringGetTextConcat((XmString) s);
    XmTextFieldSetString(w, str);
    if (str != NULL) XtFree(str);
    break;
  case XmFORMAT_MBYTE:
    XmTextFieldSetString(w, (char*) s);
    break;
  case XmFORMAT_WCS:
    XmTextFieldSetStringWcs(w, (wchar_t *) s);
  }
}

/*ARGSUSED*/
static int
TextFieldPreferredValue(Widget w) /* unused */
{
  return(XmFORMAT_MBYTE);
}

/*
 * XmRCallProc routine for checking text.font_list before setting it to NULL
 * if no value is specified for both XmNrenderTable and XmNfontList.
 * If "check_set_render_table" == True, then function has been called twice
 * on same widget, thus resource needs to be set NULL, otherwise leave it
 * alone.
 */
/* ARGSUSED */
static void 
CheckSetRenderTable(Widget wid,
		    int offset,
		    XrmValue *value)
{
  XmTextFieldWidget tf = (XmTextFieldWidget)wid;

  if (tf->text.check_set_render_table)
	value->addr = NULL;
  else {
	tf->text.check_set_render_table = True;
	value->addr = (char*)&(tf->text.font_list);
  }
}

static Boolean 
TextFieldRemove(Widget w,
		XEvent *event)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  XmTextPosition left = tf->text.prim_pos_left, right = tf->text.prim_pos_right;
  XmAnyCallbackStruct cb;

  if (TextF_Editable(tf) == False)
    return False;
  
  TextFieldResetIC(w);
  if (!tf->text.has_primary || left == right) {
    tf->text.prim_anchor = TextF_CursorPosition(tf);
    return False;
  }
  
  if (_XmTextFieldReplaceText(tf, event, left, right, NULL, 0, True)) {
    _XmTextFieldStartSelection(tf, TextF_CursorPosition(tf),
			       TextF_CursorPosition(tf),
			       XtLastTimestampProcessed(XtDisplay(w)));
    tf->text.pending_off = False;
    cb.reason = XmCR_VALUE_CHANGED;
    cb.event = event;
    XtCallCallbackList((Widget) tf, TextF_ValueChangedCallback(tf),
		       (XtPointer) &cb);
  }
  
  tf->text.prim_anchor = TextF_CursorPosition(tf);
  
  return True;
}

/* ARGSUSED */
static Boolean 
TextFieldGetBaselines(Widget w,
		      Dimension ** baselines,
		      int *line_count)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  Dimension *base_array;
  
  *line_count = 1;
  
  base_array = (Dimension *) XtMalloc(sizeof(Dimension));
  
  base_array[0] = tf->text.margin_top + tf->primitive.shadow_thickness +
    tf->primitive.highlight_thickness + TextF_FontAscent(tf);
  
  *baselines = base_array;
  
  return (TRUE);
}

static Boolean
TextFieldGetDisplayRect(Widget w,
			XRectangle * display_rect)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  Position margin_width = TextF_MarginWidth(tf) +
    tf->primitive.shadow_thickness +
      tf->primitive.highlight_thickness;
  Position margin_top = tf->text.margin_top + tf->primitive.shadow_thickness +
    tf->primitive.highlight_thickness;
  Position margin_bottom = tf->text.margin_bottom +
    tf->primitive.shadow_thickness +
      tf->primitive.highlight_thickness;
  (*display_rect).x = margin_width;
  (*display_rect).y = margin_top;
  (*display_rect).width = tf->core.width - (2 * margin_width);
  (*display_rect).height = tf->core.height - (margin_top + margin_bottom);
  
  return(TRUE);
}


/* ARGSUSED */
static void
TextFieldMarginsProc(Widget w,
		     XmBaselineMargins *margins_rec)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  
  if (margins_rec->get_or_set == XmBASELINE_SET) {
    tf->text.margin_top = margins_rec->margin_top;
  } else {
    margins_rec->margin_top = tf->text.margin_top;
    margins_rec->margin_bottom = tf->text.margin_bottom;
    margins_rec->text_height = TextF_FontAscent(tf) + TextF_FontDescent(tf);
    margins_rec->shadow = tf->primitive.shadow_thickness;
    margins_rec->highlight = tf->primitive.highlight_thickness;
    margins_rec->margin_height = 0;
  }
}


/*
 * This procedure and _XmTextFieldReplaceText are almost same.
 * The difference is that this function doesn't call user's callbacks,
 * like XmNmodifyVerifyCallback.
 */
static Boolean
_XmTextFieldReplaceTextForPreedit(XmTextFieldWidget tf,
                                  XmTextPosition replace_prev,
                                  XmTextPosition replace_next,
                                  char *insert,
                                  int insert_length,
                                  Boolean move_cursor )
{
  int replace_length, i;
  char *src, *dst;
  wchar_t *wc_src, *wc_dst;
  XmAnyCallbackStruct cb;
  int delta = 0;
  XmTextPosition cursorPos, newInsert;
  XmTextPosition old_pos = replace_prev;
  XmTextPosition redisplay_start;
  int free_insert = (int)False;

  VerifyBounds(tf, &replace_prev, &replace_next);

  if (!TextF_Editable(tf)) {
     if (tf->text.verify_bell) XBell(XtDisplay((Widget)tf), 0);
     return False;
 }

  /*
   * If composite sequences were supported, we had to
   * redisplay from the nearest composite sequence break.
   * But for current implementation, just use old_pos.
   */
  redisplay_start = old_pos;

  replace_length = (int) (replace_next - replace_prev);
  delta = insert_length - replace_length;

 /* Disallow insertions that go beyond max length boundries.
  */
  if ((delta >= 0) &&
      ((tf->text.string_length + delta) - (TextF_MaxLength(tf)) > 0)) {
      if (tf->text.verify_bell) XBell(XtDisplay(tf), 0);
      return False;
  }

  newInsert = TextF_CursorPosition(tf);

 /* make sure selections are turned off prior to changeing text */
  if (tf->text.has_primary &&
      tf->text.prim_pos_left != tf->text.prim_pos_right)
     doSetHighlight((Widget)tf, tf->text.prim_pos_left,
                             tf->text.prim_pos_right, XmHIGHLIGHT_NORMAL);

  _XmTextFieldDrawInsertionPoint(tf, False);

  /* Allocate more space if we need it.
   */
  if (tf->text.max_char_size == 1){
  if (tf->text.string_length + insert_length - replace_length >=
      tf->text.size_allocd)
    {
      tf->text.size_allocd += MAX(insert_length + TEXT_INCREMENT,
                                        (tf->text.size_allocd * 2));
      tf->text.value = (char *) XtRealloc((char*)TextF_Value(tf),
                              (unsigned) (tf->text.size_allocd * sizeof(char)));
    }
  } else {
 if ((tf->text.string_length + insert_length - replace_length) *
                                        sizeof(wchar_t) >= tf->text.size_allocd)
    {
      tf->text.size_allocd += MAX(insert_length + TEXT_INCREMENT,
                                        (tf->text.size_allocd * 2));
      tf->text.wc_value = (wchar_t *) XtRealloc((char*)TextF_WcValue(tf),
                           (unsigned) (sizeof(wchar_t) * tf->text.size_allocd));
    }
  }

  if (tf->text.max_char_size == 1) {
     if (replace_length > insert_length)
       /* We need to shift the text at and after replace_next to the left. */
       for (src = TextF_Value(tf) + replace_next,
            dst = src + (insert_length - replace_length),
            i = (int) ((tf->text.string_length + 1) - replace_next);
            i > 0;
            ++src, ++dst, --i)
         *dst = *src;
     else if (replace_length < insert_length)
       /* We need to shift the text at and after replace_next to the right. */
       /* Need to add 1 to string_length to handle the NULL terminator on */
       /* the string. */
       for (src = TextF_Value(tf) + tf->text.string_length,
            dst = src + (insert_length - replace_length),
            i = (int) ((tf->text.string_length + 1) - replace_next);
            i > 0;
            --src, --dst, --i)
         *dst = *src;

    /* Update the string.
     */
     if (insert_length != 0) {
        for (src = insert,
             dst = TextF_Value(tf) + replace_prev,
             i = insert_length;
             i > 0;
             ++src, ++dst, --i)
          *dst = *src;
     }
   } else {  /* have wchar_t* data */
     if (replace_length > insert_length)
       /* We need to shift the text at and after replace_next to the left. */
       for (wc_src = TextF_WcValue(tf) + replace_next,
            wc_dst = wc_src + (insert_length - replace_length),
            i = (int) ((tf->text.string_length + 1) - replace_next);
            i > 0;
            ++wc_src, ++wc_dst, --i)
         *wc_dst = *wc_src;
     else if (replace_length < insert_length)
       /* We need to shift the text at and after replace_next to the right. */
       /* Need to add 1 to string_length to handle the NULL terminator on */
       /* the string. */
       for (wc_src = TextF_WcValue(tf) + tf->text.string_length,
            wc_dst = wc_src + (insert_length - replace_length),
            i = (int) ((tf->text.string_length + 1) - replace_next);
            i > 0;
            --wc_src, --wc_dst, --i)
         *wc_dst = *wc_src;

    /* Update the string.
     */
     if (insert_length != 0) {
       for (wc_src = (wchar_t *)insert,
             wc_dst = TextF_WcValue(tf) + replace_prev,
             i = insert_length;
             i > 0;
             ++wc_src, ++wc_dst, --i)
          *wc_dst = *wc_src;
     }
   }

  tf->text.string_length += insert_length - replace_length;

  if (move_cursor) {
     if (TextF_CursorPosition(tf) != newInsert) {
        if (newInsert > tf->text.string_length) {
           cursorPos = tf->text.string_length;
        } else if (newInsert < 0) {
           cursorPos = 0;
        } else {
           cursorPos = newInsert;
        }
     } else
      cursorPos = replace_next + (insert_length - replace_length);
     (void) SetDestination((Widget)tf, cursorPos, False,
                        XtLastTimestampProcessed(XtDisplay((Widget)tf)));
     PreeditSetCursorPosition(tf, cursorPos);
  }

  if (TextF_ResizeWidth(tf) && tf->text.do_resize) {
     AdjustSize(tf);
  } else {
     AdjustText(tf, TextF_CursorPosition(tf), False);

     /*
      * If composite sequences where supported, we had to
      * adjust redisplay_start once more here, since the widget
      * value was updated.
      * But for current implementation, there is no need
      * to do so.
      */

     RedisplayText(tf, redisplay_start, tf->text.string_length);
  }

  _XmTextFieldDrawInsertionPoint(tf, True);
  if (free_insert) XtFree(insert);
  return True;
}

/*
 * This function shows the correspondence of rendition data between the input
 * server and XmTextField
 */
static XmHighlightMode
_XimFeedbackToXmHighlightMode(XIMFeedback fb)
{
    switch (fb) {
      case XIMReverse:
        return(XmHIGHLIGHT_SELECTED);
      case XIMUnderline:
        return(XmHIGHLIGHT_SECONDARY_SELECTED);
      case XIMHighlight:
        return(XmHIGHLIGHT_NORMAL);
      case XIMPrimary:
	return(XmHIGHLIGHT_SELECTED);
      case XIMSecondary:
	return(XmHIGHLIGHT_SECONDARY_SELECTED);
      case XIMTertiary:
        return(XmHIGHLIGHT_SELECTED);
      default:
        return(XmHIGHLIGHT_NORMAL);
    }
}
/*
 * This function treats the rendition data.
 */
static void
PreeditSetRendition(Widget w,
                    XIMPreeditDrawCallbackStruct* data)
{
    XIMText *text = data->text;
    int cnt;
    XIMFeedback fb;
    XmTextPosition prestart = PreStart((XmTextFieldWidget)w)+data->chg_first, left, right;
    XmHighlightMode mode;
    XmTextFieldWidget tf = (XmTextFieldWidget)w;

    if (!text->length) {
        return;
    }

    if (!text->feedback)
        return;

    fb = text->feedback[0];     /* initial feedback */
    left = right = prestart;    /* mode start/end position */
    mode = _XimFeedbackToXmHighlightMode(fb); /* mode */
    cnt = 1;                    /* counter initialize */

    while (cnt < (int)text->length) {
        if (fb != text->feedback[cnt]) {
            right = prestart + cnt;
            doSetHighlight(w, left, right, mode);

            left = right;       /* start position update */
            fb = text->feedback[cnt]; /* feedback update */
            mode = _XimFeedbackToXmHighlightMode(fb);
        }
        cnt++;                  /* counter increment */
    }
    doSetHighlight(w, left, (prestart + cnt), mode);
                                /* for the last segment */
}

/*
 * This function and _XmTextFieldSetCursorPosition are almost same. The
 * difference is that this function don't call user's callbacks link
 * XmNmotionVerifyCallback.
 */
static void
PreeditSetCursorPosition(XmTextFieldWidget tf,
                         XmTextPosition position)
{
    int i;
    _XmHighlightRec *hl_list = tf->text.highlight.list;

    if (position < 0) position = 0;

    if (position > tf->text.string_length)
       position = tf->text.string_length;

    _XmTextFieldDrawInsertionPoint(tf, False);

    TextF_CursorPosition(tf) = position;
    for (i = tf->text.highlight.number - 1; i >= 0; i--){
       if (position >= hl_list[i].position || i == 0)
          break;
    }

    if (position == hl_list[i].position)
       ResetImageGC(tf);
    else if (hl_list[i].mode != XmHIGHLIGHT_SELECTED)
       ResetImageGC(tf);
    else
       InvertImageGC(tf);

    ResetClipOrigin(tf);

    tf->text.refresh_ibeam_off = True;
    _XmTextFieldDrawInsertionPoint(tf, True);
}


static void PreeditVerifyReplace(XmTextFieldWidget tf, 
				 XmTextPosition start,
				 XmTextPosition end,
				 char *insert,
				 char insert_length,
				 XmTextPosition cursor,
				 Boolean *end_preedit)

{
  FUnderVerifyPreedit(tf) = True;
  _XmTextFieldReplaceText(tf, NULL, start, end, insert, insert_length, True);
  FUnderVerifyPreedit(tf) = False;
  if (FVerifyCommitNeeded(tf)) {
    TextFieldResetIC((Widget) tf);
    *end_preedit = True;
  }
  _XmTextFieldSetCursorPosition(tf, NULL, cursor, False, True);
} 
  
   

/*
 * This is the function set to XNPreeditStartCallback resource.
 * This function is called when the preedit process starts.
 * Initialize the preedit data and also treat pending delete.
 */
static int
PreeditStart(XIC xic,
             XPointer client_data,
             XPointer call_data)
{
    XmTextPosition cursorPos, nextPos, lastPos;
    Boolean replace_res, pending_delete = False;
    wchar_t *wc;
    char *mb;
    Widget w = (Widget) client_data;
    XmTextFieldWidget tf = (XmTextFieldWidget) client_data;

    tf->text.onthespot->over_len = 0;
    tf->text.onthespot->over_str = NULL;
    tf->text.onthespot->over_maxlen = 0;

    /* If TextField is not editable, returns 0. So input server never */
    /* call Preedit Draw callback */
    if (!TextF_Editable(tf)) {
        if (tf->text.verify_bell) XBell(XtDisplay((Widget)tf), 0);
        tf->text.onthespot->under_preedit = False;
        return 0;
    }

    if (NeedsPendingDeleteDisjoint(tf)){
        _XmTextFieldDrawInsertionPoint(tf, False);
        if (!XmTextFieldGetSelectionPosition(w, &cursorPos, &nextPos) ||
                                                cursorPos == nextPos) {
          tf->text.prim_anchor = TextF_CursorPosition(tf);
        }
        pending_delete = True;

        tf->text.prim_anchor = TextF_CursorPosition(tf);

        replace_res = _XmTextFieldReplaceText(tf,
                        NULL, cursorPos, nextPos, NULL, 0, True);

        if (replace_res){
            if (pending_delete)
                XmTextFieldSetSelection(w, TextF_CursorPosition(tf),
                        TextF_CursorPosition(tf),
                        XtLastTimestampProcessed(XtDisplay((Widget)tf)));

            CheckDisjointSelection(w, TextF_CursorPosition(tf),
                        XtLastTimestampProcessed(XtDisplay((Widget)tf)));

            _XmTextFieldSetCursorPosition(tf,
                        NULL,
                        TextF_CursorPosition(tf), False, True);
        }
        _XmTextFieldDrawInsertionPoint(tf, True);
    }

    PreStart(tf) = PreEnd(tf) = PreCursor(tf)
        = TextF_CursorPosition(tf);
    tf->text.onthespot->under_preedit = True;

    if (tf->text.overstrike) {
       lastPos = tf->text.string_length;
       tf->text.onthespot->over_len = lastPos - PreCursor(tf);

            if (tf->text.max_char_size == 1){
                mb = XtMalloc(tf->text.onthespot->over_len + 1);
                bcopy(&tf->text.value[PreStart(tf)], mb,
                                        tf->text.onthespot->over_len);
                mb[tf->text.onthespot->over_len] = '\0';
                tf->text.onthespot->over_str = mb;
            } else {
                wc = (wchar_t *) XtMalloc(
                        (tf->text.onthespot->over_len+1)*sizeof(wchar_t));
                bcopy((char *)&tf->text.wc_value[PreStart(tf)], (char *)wc,
                                tf->text.onthespot->over_len*sizeof(wchar_t));
                wc[tf->text.onthespot->over_len] = (wchar_t)'\0';
                tf->text.onthespot->over_str = (char *)wc;
            }
    }

    return (-1);
}

/*
 * This is the function set to XNPreeditDoneCallback resource.
 * This function is called when the preedit process is finished.
 */
static void
PreeditDone(XIC xic,
            XPointer client_data,
            XPointer call_data)
{
    Boolean replace_res;
    XmTextFieldWidget tf = (XmTextFieldWidget)client_data;
    Widget p = (Widget) tf;
    Boolean need_verify, end_preedit = False;

    if (!TextF_Editable(tf))
        return;
 
    while (!XtIsShell(p))
	p = XtParent(p);
    XtVaGetValues(p, XmNverifyPreedit, &need_verify, NULL);

    if (PreEnd(tf) > PreStart(tf)) {
      if (need_verify) {
        PreeditVerifyReplace(tf, PreStart(tf), PreEnd(tf), NULL, 0,
                                PreStart(tf), &end_preedit);
        if (end_preedit) return;
      }
      else
        _XmTextFieldReplaceTextForPreedit(tf, PreStart(tf),
                        PreEnd(tf), NULL, 0, True );
    }

    if (tf->text.overstrike){
      if (need_verify) {
	int cur = PreStart(tf);
 	PreeditVerifyReplace(tf, PreStart(tf), PreStart(tf), 
				(char*) tf->text.onthespot->over_str,
				tf->text.onthespot->over_maxlen,	
                                PreStart(tf), &end_preedit);
	if (end_preedit) return;
      }
      else {
        _XmTextFieldDrawInsertionPoint(tf, False);
        replace_res = _XmTextFieldReplaceTextForPreedit(tf, PreStart(tf),
                        PreStart(tf), (char*) tf->text.onthespot->over_str,
                        tf->text.onthespot->over_maxlen, True);
        TextF_CursorPosition(tf) = PreStart(tf);
        PreeditSetCursorPosition(tf, TextF_CursorPosition(tf));
        _XmTextFieldDrawInsertionPoint(tf, True);
      }
      XtFree((char *)tf->text.onthespot->over_str);
      tf->text.onthespot->over_len = tf->text.onthespot->over_maxlen = 0;
    }

    PreStart(tf) = PreEnd(tf) = PreCursor(tf) = 0;
    tf->text.onthespot->under_preedit = False;
}

/*
 * This is the function set to XNPreeditDrawCallback resource.
 * This function is called when the input server requests XmTextField
 * to draw a preedit string.
 */
static void
PreeditDraw(XIC xic,
            XPointer client_data,
            XIMPreeditDrawCallbackStruct *call_data)
{
    Widget w = (Widget) client_data;
    XmTextFieldWidget tf = (XmTextFieldWidget) client_data;
    int escapement, insert_length = 0;
    char *mb = NULL, *over_mb;
    wchar_t *wc = NULL, *over_wc, *tab_wc, *recover_wc;
    XmTextPosition startPos, endPos, cursorPos, rest_len, tmp_end;
    Boolean replace_res;
    XRectangle overall_ink;
    int i;
    int recover_len=0;
    char *ptr=NULL;
    Widget p =w;
    Boolean need_verify, end_preedit = False;

    if (!TextF_Editable(tf))
        return;

    if (call_data->text &&
        (insert_length = call_data->text->length) > TEXT_MAX_INSERT_SIZE)
        return;

    if (call_data->chg_length>PreEnd(tf)-PreStart(tf))
        call_data->chg_length = PreEnd(tf)-PreStart(tf);

    while (!XtIsShell(p))
	p = XtParent(p);
    XtVaGetValues(p, XmNverifyPreedit, &need_verify, NULL);

    _XmTextFieldDrawInsertionPoint(tf, False);
    doSetHighlight(w, PreStart(tf)+call_data->chg_first,
        PreStart(tf)+call_data->chg_first + call_data->chg_length,
        XmHIGHLIGHT_NORMAL);


    if (!tf->text.overstrike && (!call_data->text || !insert_length)) {
        startPos = PreStart(tf) + call_data->chg_first;
        endPos = startPos + call_data->chg_length;
	PreEnd(tf) -= endPos - startPos;
	if (need_verify) {
	  PreeditVerifyReplace(tf, startPos, endPos, NULL, 0, 
					startPos, &end_preedit);
	  if (end_preedit) {
	    _XmTextFieldDrawInsertionPoint(tf, True);
	    return;
	  }
	}
	else {
          replace_res = _XmTextFieldReplaceTextForPreedit(tf, startPos,
                                             endPos, NULL, 0, True);
	}
	_XmTextFieldDrawInsertionPoint(tf, True);
        return;
    }

    if (call_data->text) {
    if ((call_data->text->encoding_is_wchar &&
         !call_data->text->string.wide_char) ||
        (!call_data->text->encoding_is_wchar &&
         !call_data->text->string.multi_byte)){

        PreeditSetRendition(w, call_data);

        PreeditSetCursorPosition(tf, TextF_CursorPosition(tf));
        _XmTextFieldDrawInsertionPoint(tf, True);
        return;
    }
    }

    if (insert_length > 0){
        if (TextF_UseFontSet(tf)){

            if (call_data->text->encoding_is_wchar){
                escapement = XwcTextExtents((XFontSet)TextF_Font(tf),
                        call_data->text->string.wide_char, insert_length,
                        &overall_ink, NULL);
           	tab_wc = (wchar_t*) XtMalloc((unsigned)(1+1) * sizeof(wchar_t));
                mbstowcs(tab_wc, "\t", 1);
                if ( escapement == 0 && overall_ink.width == 0 &&
                    wcschr(call_data->text->string.wide_char, *tab_wc) == 0){
                        /* cursor on */
		    XtFree((char *) tab_wc);
                    return;
                }
	        XtFree((char *) tab_wc);
            } else {
                mb = XtMalloc((insert_length+1)*(tf->text.max_char_size));
                strcpy(mb, call_data->text->string.multi_byte);
                escapement = XmbTextExtents((XFontSet)TextF_Font(tf),
                        mb, strlen(mb), &overall_ink, NULL);
                if ( escapement == 0 && overall_ink.width == 0 &&
                    strchr(call_data->text->string.multi_byte, '\t') == 0){
                        /* cursor on */
                    if (mb)
                       XtFree(mb);
                    return;
                }
            }
        }
    }
    else {
        mb = XtMalloc(4);
        mb[0] = '\0';
        wc = (wchar_t *) XtMalloc((unsigned) sizeof(wchar_t));
        wc[0] = (wchar_t) '\0';
    }

    startPos = PreStart(tf) + call_data->chg_first;
    endPos = startPos + call_data->chg_length;

   if (tf->text.overstrike){
        startPos = PreStart(tf) + call_data->chg_first;
        tmp_end = (XmTextPosition)(PreEnd(tf) + insert_length -
                                                call_data->chg_length);
        if (tf->text.onthespot->over_maxlen < tmp_end - PreStart(tf)){
            if (tmp_end - PreStart(tf) > tf->text.onthespot->over_len){
                endPos = startPos + call_data->chg_length;
                tf->text.onthespot->over_maxlen = tf->text.onthespot->over_len;
            } else {
                endPos = PreEnd(tf) + tmp_end - PreStart(tf) -
                                tf->text.onthespot->over_maxlen;
                tf->text.onthespot->over_maxlen = tmp_end - PreStart(tf);
            }
        } else
        if (tf->text.onthespot->over_maxlen > tmp_end - PreStart(tf)) {
            endPos = PreEnd(tf);
            recover_len = tf->text.onthespot->over_maxlen - tmp_end +
                                PreStart(tf);
            tf->text.onthespot->over_maxlen = tmp_end - PreStart(tf);
        } else
            endPos = startPos + call_data->chg_length;

        rest_len = (XmTextPosition)(PreEnd(tf) - PreStart(tf) -
                        call_data->chg_first - call_data->chg_length);
        if (rest_len){
            if (tf->text.max_char_size == 1){
                over_mb = XtMalloc(rest_len+1);
               bcopy(&tf->text.value[PreStart(tf)+call_data->chg_first+
                                call_data->chg_length], over_mb, rest_len);
                over_mb[rest_len] = '\0';
            } else {
                over_wc = (wchar_t *)XtMalloc((rest_len+1)*sizeof(wchar_t));
                bcopy((char *)&tf->text.wc_value[PreStart(tf)+
                        call_data->chg_first+call_data->chg_length],
                        (char *)over_wc, rest_len*sizeof(wchar_t));
                over_wc[rest_len] = (wchar_t)'\0';
            }
        }
    }

    if (tf->text.overstrike)
        PreEnd(tf) = startPos + insert_length;
    else
        PreEnd(tf) += insert_length - endPos + startPos;

    if (PreEnd(tf) < PreStart(tf))
        PreEnd(tf) = PreStart(tf);

    PreCursor(tf) = PreStart(tf) + call_data->caret;

    if (tf->text.max_char_size == 1) {
        if (call_data->text) {
        if (call_data->text->encoding_is_wchar){
            mb = XtMalloc((insert_length+1)*sizeof(char));
            wcstombs(mb, call_data->text->string.wide_char, insert_length);
            mb[insert_length] = '\0';
        } else
        {
            mb = XtMalloc((insert_length+1)*sizeof(char));
            strcpy(mb, call_data->text->string.multi_byte);
        }
	}

        if (tf->text.overstrike && rest_len){
            mb = XtRealloc(mb, strlen(mb)+strlen(over_mb)+1);
            strcat(mb, over_mb);
            XtFree(over_mb);
        }

        if (tf->text.overstrike && recover_len > 0) {
           mb = XtRealloc(mb, strlen(mb)+(recover_len+1));
           ptr = tf->text.onthespot->over_str + tf->text.onthespot->over_maxlen;
           i = strlen(mb);
           strncat(mb, ptr, recover_len);
           mb[i+recover_len] = '\0';
        }

	if (need_verify) {
	  PreeditVerifyReplace(tf, startPos, endPos, mb, strlen(mb),
				PreCursor(tf), &end_preedit);
	  if (end_preedit) {
	    _XmTextFieldDrawInsertionPoint(tf, True);
	    return;
	  }
	}
	else {  
          replace_res = _XmTextFieldReplaceTextForPreedit(tf, startPos,
                                             endPos, mb,
                                             strlen(mb), True);
    	  PreeditSetCursorPosition(tf, PreCursor(tf));
	}

    } else {
        if (call_data->text) {
        if (!call_data->text->encoding_is_wchar){
            wc = (wchar_t*)XtMalloc((unsigned)(insert_length+1) *
                                             sizeof(wchar_t));
            mbstowcs( wc, call_data->text->string.multi_byte,
                                                        insert_length);
        } else
        {
            wc = (wchar_t*)XtMalloc((unsigned)(insert_length+1) *
                                             sizeof(wchar_t));
            wcscpy(wc, call_data->text->string.wide_char);
        }
        wc[insert_length] = (wchar_t) '\0';
        }

        if (tf->text.overstrike && rest_len){
            wc = (wchar_t *)XtRealloc((char *)wc,
                        (insert_length+rest_len+1)*sizeof(wchar_t));
            wcscat(wc, over_wc);
            XtFree((char *)over_wc);
        }

        if (tf->text.overstrike && recover_len > 0) {
           wc = (wchar_t *)XtRealloc((char *)wc,
                       wcslen(wc)+(recover_len+1)*sizeof(wchar_t));
           ptr = XtMalloc((tf->text.onthespot->over_len+1)*sizeof(char));
           wcstombs(ptr, (wchar_t *)tf->text.onthespot->over_str,
                            tf->text.onthespot->over_len);
           ptr[tf->text.onthespot->over_len] = '\0';

           for (i=0; i < tf->text.onthespot->over_maxlen; i++) {
               ptr += mblen(ptr, 4);
           }

           recover_wc = (wchar_t*) XtMalloc((unsigned)(recover_len+1) *
                                                       sizeof(wchar_t));
           mbstowcs(recover_wc, ptr, recover_len);
           i = wcslen(wc);
           wcsncat(wc, recover_wc, recover_len);
           wc[i+recover_len] = (wchar_t) '\0';
           XtFree((char *) recover_wc);
           if (ptr)
              XtFree(ptr);
        }
	
	if (need_verify) {
          PreeditVerifyReplace(tf, startPos, endPos, (char *)wc,
				wcslen(wc), PreCursor(tf), &end_preedit);
          if (end_preedit) {
	    _XmTextFieldDrawInsertionPoint(tf, True);
	    return;
	  }
        }
        else {
          replace_res = _XmTextFieldReplaceTextForPreedit(tf, startPos,
                                             endPos, (char *)wc,
                                             wcslen(wc), True);
          PreeditSetCursorPosition(tf, PreCursor(tf));
        }
    }

    if (insert_length > 0)
       PreeditSetRendition(w, call_data);

    _XmTextFieldDrawInsertionPoint(tf, True);

    if (mb)
       XtFree(mb);
    if (wc)
       XtFree((char *) wc);
}

/*
 * This is the function set to XNPreeditCaretCallback resource.
 * This function is called when the input server requests XmTextField to move
 * the caret.
 */
static void
PreeditCaret(XIC xic,
             XPointer client_data,
             XIMPreeditCaretCallbackStruct *call_data)
{
    XmTextPosition new_position;
    XmTextFieldWidget tf = (XmTextFieldWidget)client_data;
    Widget p = (Widget) tf;
    Boolean need_verify;

    if (!TextF_Editable(tf))
        return;

    while (!XtIsShell(p))
	p = XtParent(p);
    XtVaGetValues(p, XmNverifyPreedit, &need_verify, NULL);

    _XmTextFieldDrawInsertionPoint(tf, False);
    switch (call_data->direction) {
        case XIMForwardChar:
          new_position = PreCursor(tf) + 1 - PreStart(tf);
          break;
        case XIMBackwardChar:
          new_position = PreCursor(tf) - 1 - PreStart(tf);
          break;
        case XIMAbsolutePosition:
          new_position = (XmTextPosition) call_data->position;
          break;
        default:
          new_position = PreCursor(tf) - PreStart(tf);
    }

    TextF_CursorPosition(tf) = PreCursor(tf) = PreStart(tf) + new_position;
    if (need_verify) {
	FUnderVerifyPreedit(tf) = True;
	_XmTextFieldSetCursorPosition(tf, NULL, PreCursor(tf), False, True);
	FUnderVerifyPreedit(tf) = False;
    } else 
    	PreeditSetCursorPosition(tf, TextF_CursorPosition(tf));
    _XmTextFieldDrawInsertionPoint(tf, True);
}

/*
 * 1. Call XmImMbResetIC to reset the input method and get the current
 *    preedit string.
 * 2. Set the string to XmTextField
 */
static void
TextFieldResetIC(Widget w)
{
    int insert_length, escapement, num_chars;
    char *mb, *str=NULL;
    Boolean replace_res;
    wchar_t *wc_insert_string;
    XRectangle overall_ink;
    XmTextPosition cursorPos, nextPos;
    XmTextFieldWidget tf = (XmTextFieldWidget)w;

    if (!(tf->text.onthespot->under_preedit))
        return;

    if (FVerifyCommitNeeded(tf)) {
	FVerifyCommitNeeded(tf) = False;
	str = XtMalloc((PreEnd(tf) - PreStart(tf)+1)*sizeof(wchar_t));
	if (tf->text.max_char_size == 1) {
	  bcopy(&tf->text.value[PreStart(tf)], str, 
				PreEnd(tf) - PreStart(tf));
	  str[PreEnd(tf) - PreStart(tf)] = '\0';
	}
	else { 
	  int num_bytes;
	  wchar_t *wc_string;
	  wc_string = (wchar_t *)XtMalloc((PreEnd(tf) - PreStart(tf)+1)
                                                        *sizeof(wchar_t));
          bcopy((char *)&tf->text.wc_value[PreStart(tf)], (char *)wc_string,
                                (PreEnd(tf) - PreStart(tf))*sizeof(wchar_t));
          wc_string[PreEnd(tf) - PreStart(tf)] = (wchar_t)'\0';
	  num_bytes = wcstombs(str, wc_string, 
				(PreEnd(tf) - PreStart(tf)+1)*sizeof(wchar_t)); 
	  str[num_bytes] = '\0';
	  XtFree((char *)wc_string);
	}
	XmImMbResetIC(w, &mb);
	mb = str;
    } 
    else 
    	XmImMbResetIC(w, &mb);

    if (!mb)
        return;

    if (!TextF_Editable(tf)) {
        if (tf->text.verify_bell) XBell(XtDisplay((Widget)tf), 0);
    }

    if ((insert_length = strlen(mb)) > TEXT_MAX_INSERT_SIZE)
        return;

    if (insert_length > 0) {
        if (TextF_UseFontSet(tf)){
            escapement = XmbTextExtents((XFontSet)TextF_Font(tf), mb,
                        insert_length, &overall_ink, NULL );
            if ( escapement == 0 && overall_ink.width == 0 )
                return;
        } else {
            if (!XTextWidth(TextF_Font(tf), mb, insert_length))
                return;
        }
   }

    cursorPos = nextPos = TextF_CursorPosition(tf);

    if (tf->text.overstrike) {
        if (nextPos != tf->text.string_length) nextPos++;
    }
    if (tf->text.max_char_size == 1) {
        replace_res = _XmTextFieldReplaceText(tf, NULL, cursorPos,
                                             nextPos, mb,
                                             insert_length, True);
    } else {
        mb[insert_length] = '\0';
        wc_insert_string = (wchar_t*)XtMalloc((unsigned)(insert_length+1) *
                                             sizeof(wchar_t));
        num_chars = mbstowcs( wc_insert_string, mb, insert_length+1);
        replace_res = _XmTextFieldReplaceText(tf, NULL, cursorPos,
                nextPos, (char*) wc_insert_string, num_chars, True);
        XtFree((char *)wc_insert_string);
    }

    if (replace_res)
        _XmTextFieldSetCursorPosition(tf, NULL,
                                      TextF_CursorPosition(tf), False, True);
    _XmTextFieldDrawInsertionPoint(tf, True);
    if (str) XtFree(str);

}


/***********************************<->***************************************

 *                              Public Functions                             *
 ***********************************<->***************************************/

char * 
XmTextFieldGetString(Widget w)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  char *temp_str;
  int ret_val = 0;
  _XmWidgetToAppContext(w);

  _XmAppLock(app);
  if (tf->text.string_length > 0) {
    if (tf->text.max_char_size == 1) {
      temp_str = XtNewString(TextF_Value(tf));
      _XmAppUnlock(app);
      return temp_str;
    } else {
      temp_str = (char *) XtMalloc((unsigned) tf->text.max_char_size *
				   (tf->text.string_length + 1));
      ret_val = wcstombs(temp_str, TextF_WcValue(tf), 
			 (tf->text.string_length + 1)*tf->text.max_char_size);
      if (ret_val < 0) temp_str[0] = '\0';
      _XmAppUnlock(app);
      return temp_str;
    }
  }
  else {
    _XmAppUnlock(app);
    return(XtNewString(""));
  }
}

int 
XmTextFieldGetSubstring(Widget widget,
			XmTextPosition start,
			int num_chars,
			int buf_size,
			char *buffer)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) widget;
  int ret_value = XmCOPY_SUCCEEDED;
  int n_bytes = 0;
  int wcs_ret = 0;
  _XmWidgetToAppContext(widget);

  _XmAppLock(app);
  if (tf->text.max_char_size != 1)
    n_bytes = _XmTextFieldCountBytes(tf, TextF_WcValue(tf)+start, num_chars);
  else
    n_bytes = num_chars; 
  
  if (buf_size < n_bytes + 1) {
    _XmAppUnlock(app);
    return XmCOPY_FAILED;
  }
  
  if (start + num_chars > tf->text.string_length) {
    num_chars = (int) (tf->text.string_length - start);
    if (tf->text.max_char_size != 1)
      n_bytes = _XmTextFieldCountBytes(tf, TextF_WcValue(tf)+start,
				       num_chars);
    else
      n_bytes = num_chars; 
    ret_value = XmCOPY_TRUNCATED;
  }
  
  if (num_chars > 0) {
    if (tf->text.max_char_size == 1) {
      (void)memcpy((void*)buffer, (void*)&TextF_Value(tf)[start], num_chars);
    } else {
      wcs_ret = wcstombs(buffer, &TextF_WcValue(tf)[start], n_bytes);
      if (wcs_ret < 0) n_bytes = 0;
    }
    buffer[n_bytes] = '\0';
  } else
    ret_value = XmCOPY_FAILED;
  
  _XmAppUnlock(app);
  return (ret_value);
}


wchar_t *
XmTextFieldGetStringWcs(Widget w)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  wchar_t *temp_wcs;
  int num_wcs = 0;
  _XmWidgetToAppContext(w);

  _XmAppLock(app);
  if (tf->text.string_length > 0) {
    temp_wcs = (wchar_t*) XtMalloc((unsigned) sizeof(wchar_t) *
				   (tf->text.string_length + 1));
    if (tf->text.max_char_size != 1) {
      (void)memcpy((void*)temp_wcs, (void*)TextF_WcValue(tf), 
		   sizeof(wchar_t) * (tf->text.string_length + 1));
    } else {
      num_wcs = mbstowcs(temp_wcs, TextF_Value(tf),
			 tf->text.string_length + 1);
      if (num_wcs < 0) temp_wcs[0] = (wchar_t)0L;
    }
    _XmAppUnlock(app);
    return temp_wcs;
  } else {
    temp_wcs = (wchar_t*) XtMalloc((unsigned) sizeof(wchar_t));
    temp_wcs[0] = (wchar_t)0L; /* put a wchar_t NULL in position 0 */
    _XmAppUnlock(app);
    return temp_wcs;
  }
}

int 
XmTextFieldGetSubstringWcs(Widget widget,
			   XmTextPosition start,
			   int num_chars,
			   int buf_size,
			   wchar_t *buffer)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) widget;
  int ret_value = XmCOPY_SUCCEEDED;
  int num_wcs = 0;
  _XmWidgetToAppContext(widget);

  _XmAppLock(app);
  if (start + num_chars > tf->text.string_length) {
    num_chars = (int) (tf->text.string_length - start);
    ret_value = XmCOPY_TRUNCATED;
  }
  
  if (buf_size < num_chars + 1) {
    _XmAppUnlock(app);
    return XmCOPY_FAILED;
  }
  
  if (num_chars > 0) {
    if (tf->text.max_char_size == 1) {
      num_wcs = mbstowcs(buffer, &TextF_Value(tf)[start], num_chars);
      if (num_wcs < 0) num_chars = 0;
    } else {
      (void)memcpy((void*)buffer, (void*)&TextF_WcValue(tf)[start], 
		   (size_t) num_chars * sizeof(wchar_t));
    }
    buffer[num_chars] = '\0';
  } else if (num_chars == 0) {
    buffer[num_chars] = '\0';
  } else
    ret_value = XmCOPY_FAILED;

  _XmAppUnlock(app);
  return (ret_value);
}


XmTextPosition 
XmTextFieldGetLastPosition(Widget w)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  XmTextPosition ret_val;
  _XmWidgetToAppContext(w);

  _XmAppLock(app); 
  ret_val = (tf->text.string_length);
  _XmAppUnlock(app);
  return ret_val;
}

void 
XmTextFieldSetString(Widget w,
		     char *value)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  XmAnyCallbackStruct cb;
  XmTextPosition fromPos, toPos, newInsert;
  int length;
  int free_insert = False;
  int ret_val = 0;
  char * tmp_ptr;
  char * mod_value = NULL;
  _XmWidgetToAppContext(w);

  _XmAppLock(app); 
  TextFieldResetIC(w);
  fromPos = 0;
  
  if (value == NULL) value = "";
  toPos = tf->text.string_length;
  if (tf->text.max_char_size == 1)
      length = strlen(value);
  else {
      for (length = 0, tmp_ptr = value, ret_val = mblen(tmp_ptr, MB_CUR_MAX);
	   ret_val > 0; 
	   ret_val = mblen(tmp_ptr, MB_CUR_MAX)){
	 if (ret_val < 0){
	    length = 0; /* If error, treat the whole string as bad */
	    break;
	 } else {
	    length += ret_val;
	    tmp_ptr += ret_val;
	 }
      }
    }

  if (XtIsSensitive(w) && tf->text.has_focus)
    ChangeBlinkBehavior(tf, False);
  _XmTextFieldDrawInsertionPoint(tf, False);
  
  if (TextF_ModifyVerifyCallback(tf) || TextF_ModifyVerifyCallbackWcs(tf)) {
    /* If the function ModifyVerify() returns false then don't
     * continue with the action.
     */
      if (tf->text.max_char_size == 1) {
	  if (!ModifyVerify(tf, NULL, &fromPos, &toPos,
			    &value, &length, &newInsert, &free_insert)) {
	      if (tf->text.verify_bell) XBell(XtDisplay(w), 0);
	      if (free_insert) XtFree(value);
	      _XmAppUnlock(app);
	      return;
	  }
      } else {
	  wchar_t * wbuf;
	  wchar_t * orig_wbuf;
	  wbuf = (wchar_t*)XtMalloc((unsigned)
				    ((strlen(value) + 1) * sizeof(wchar_t)));
	  length = mbstowcs(wbuf, value, (size_t)(strlen(value) + 1));
	  if (length < 0) length = 0;
	  orig_wbuf = wbuf; /* save the pointer to free later */

	  if (!ModifyVerify(tf, NULL, &fromPos, &toPos, (char**)&wbuf, 
			    &length, &newInsert, &free_insert)) {
	      if (tf->text.verify_bell) XBell(XtDisplay(w), 0);
	      if (free_insert) XtFree((char*)wbuf);
	      XtFree((char*)orig_wbuf);
	      _XmAppUnlock(app);
	      return;
	  }
	  else {
	      mod_value = XtMalloc((unsigned)
				   ((length + 1) * tf->text.max_char_size));
	      ret_val = wcstombs(mod_value, wbuf, (size_t)
				 ((length + 1) * tf->text.max_char_size));
	      if (free_insert) {
		  XtFree((char*)wbuf);
		  free_insert = False;
	      }
	      XtFree((char*)orig_wbuf);
	      if (ret_val < 0){
		  XtFree(mod_value);
		  length = strlen(value);
	      } else {
		  value = mod_value;
	      }
	  }
      }
  }
    
  TextFieldSetHighlight((XmTextFieldWidget) w, 0,
			tf->text.string_length, XmHIGHLIGHT_NORMAL);
  
  if (tf->text.max_char_size == 1)
    XtFree(TextF_Value(tf));
  else   /* convert to wchar_t before calling ValidateString */
    XtFree((char *)TextF_WcValue(tf));
  
  ValidateString(tf, value, False);
  if(mod_value) XtFree(mod_value);
  
  tf->text.pending_off = True;    
  
  SetCursorPosition(tf, NULL, 0, True, True, False, DontCare);
  
  if (TextF_ResizeWidth(tf) && tf->text.do_resize)
    AdjustSize(tf);
  else {
    tf->text.h_offset = TextF_MarginWidth(tf) + 
      tf->primitive.shadow_thickness +
	tf->primitive.highlight_thickness;
    if (!AdjustText(tf, TextF_CursorPosition(tf), False))
      RedisplayText(tf, 0, tf->text.string_length);
  }
  
  cb.reason = XmCR_VALUE_CHANGED;
  cb.event = NULL;
  XtCallCallbackList(w, TextF_ValueChangedCallback(tf), (XtPointer) &cb);
  
  tf->text.refresh_ibeam_off = True;
  
  if (XtIsSensitive(w) && tf->text.has_focus)
    ChangeBlinkBehavior(tf, True);
  _XmTextFieldDrawInsertionPoint(tf, True);
  if (free_insert) XtFree(value);
  _XmAppUnlock(app);
}


void 
XmTextFieldSetStringWcs(Widget w,
			wchar_t *wc_value)
{
  
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  char * tmp;
  wchar_t *tmp_wc;
  int num_chars = 0;
  int result;
  _XmWidgetToAppContext(w);

  _XmAppLock(app);
  TextFieldResetIC(w);
  for (num_chars = 0, tmp_wc = wc_value; *tmp_wc != (wchar_t)0L; num_chars++)
    tmp_wc++;  /* count number of wchar_t's */
  
  tmp = XtMalloc((unsigned) (num_chars + 1) * tf->text.max_char_size);
  result = wcstombs(tmp, wc_value, (num_chars + 1) * tf->text.max_char_size);
  
  if (result == (size_t) -1) /* if wcstombs fails, it returns (size_t) -1 */
    tmp = "";               /* if invalid data, pass in the empty string */

  XmTextFieldSetString(w, tmp);
  
  XtFree(tmp);
  _XmAppUnlock(app);
}


static void 
TextFieldReplace(Widget w,
		 XmTextPosition from_pos,
		 XmTextPosition to_pos,
		 char *value, 
		 int is_wc)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  int save_maxlength = TextF_MaxLength(tf);
  Boolean save_editable = TextF_Editable(tf);
  Boolean deselected = False;
  Boolean rep_result = False;
  wchar_t *wc_value = (wchar_t *)value;
  int length = 0;
  XmAnyCallbackStruct cb;
  _XmWidgetToAppContext(w);

  _XmAppLock(app);
  if (value == NULL) value = "";
  
  VerifyBounds(tf, &from_pos, &to_pos);
  
  if (tf->text.has_primary) {
    if ((tf->text.prim_pos_left > from_pos && 
	 tf->text.prim_pos_left < to_pos) || 
	(tf->text.prim_pos_right >from_pos && 
	 tf->text.prim_pos_right < to_pos) ||
	(tf->text.prim_pos_left <= from_pos && 
	 tf->text.prim_pos_right >= to_pos)) {
      _XmTextFieldDeselectSelection(w, False,
				    XtLastTimestampProcessed(XtDisplay(w)));
      deselected = True;
    }
  }
  
  TextF_Editable(tf) = True;
  TextF_MaxLength(tf) = INT_MAX;
  if (is_wc) {
    /* Count the number of wide chars in the array */
    for (length = 0; wc_value[length] != (wchar_t)0L; length++)
      /*EMPTY*/;
    if (tf->text.max_char_size != 1) {
      rep_result = _XmTextFieldReplaceText(tf, NULL, from_pos, to_pos,
					 (char*)wc_value, length, False);
    } else {  /* need to convert to char* before calling Replace */
      value = XtMalloc((unsigned) (length + 1) * tf->text.max_char_size);
      length = wcstombs(value, wc_value, 
			   (length + 1) * tf->text.max_char_size);
      if (length < 0) {        /* if wcstombs fails, it returns -1 */
	value = "";            /* if invalid data, pass in the empty string */
	length = 0;
      }
      rep_result = _XmTextFieldReplaceText(tf, NULL, from_pos, to_pos,
					   (char*)value, length, False);
      XtFree(value);
    }
  } else {
    if (tf->text.max_char_size == 1) {
      length = strlen(value);
      rep_result = _XmTextFieldReplaceText(tf, NULL, from_pos, 
					   to_pos, value, length, False);
    } else { /* need to convert to wchar_t* before calling Replace */
      wc_value = (wchar_t *) XtMalloc((unsigned) sizeof(wchar_t) *
				      (1 + strlen(value)));
      length = mbstowcs(wc_value, value, (unsigned) (strlen(value) + 1));
      if (length < 0) {
	wc_value[0] = (wchar_t) 0L;/* if invalid data, pass in empty string */ 
	length = 0;
      }
      rep_result = _XmTextFieldReplaceText(tf, NULL, from_pos, to_pos, 
					   (char*)wc_value, length, False);
      XtFree((char *)wc_value);
    }
  }
  if (from_pos <= TextF_CursorPosition(tf)) {
    XmTextPosition cursorPos;
    /* Replace will not move us, we still want this to happen */
    if (TextF_CursorPosition(tf) < to_pos) {
      if (TextF_CursorPosition(tf) - from_pos <= length)
	cursorPos = TextF_CursorPosition(tf);
      else
	cursorPos = from_pos + length;
    } else {
      cursorPos = TextF_CursorPosition(tf) - (to_pos - from_pos) + length;
    }
    SetCursorPosition(tf, NULL, cursorPos, True, True, False, DontCare);
  }
  TextF_Editable(tf) = save_editable;
  TextF_MaxLength(tf) = save_maxlength;
  
  /* 
   * Replace Text utilizes an optimization in deciding which text to redraw;
   * in the case that the selection has been changed (as above), this can
   * cause part/all of the replaced text to NOT be redrawn.  The following
   * AdjustText call ensures that it IS drawn in this case.
   */
  
  if (deselected)
    AdjustText(tf, from_pos, True);
  
  (void) SetDestination(w, TextF_CursorPosition(tf), False,
			XtLastTimestampProcessed(XtDisplay(w)));
  if (rep_result) {
    cb.reason = XmCR_VALUE_CHANGED;
    cb.event = NULL;
    XtCallCallbackList((Widget) tf, TextF_ValueChangedCallback(tf),
		       (XtPointer) &cb);
  }
  _XmAppUnlock(app);
}

void 
XmTextFieldReplace(Widget w,
		   XmTextPosition from_pos,
		   XmTextPosition to_pos,
		   char *value)
{
  _XmWidgetToAppContext(w);

  _XmAppLock(app);
  TextFieldReplace(w, from_pos, to_pos, value, False);
  _XmAppUnlock(app);
}


void 
XmTextFieldReplaceWcs(Widget w,
		      XmTextPosition from_pos,
		      XmTextPosition to_pos,
		      wchar_t *wc_value)
{
  _XmWidgetToAppContext(w);

  _XmAppLock(app);
  TextFieldReplace(w, from_pos, to_pos, (char *)wc_value, True);
  _XmAppUnlock(app);
}


void 
XmTextFieldInsert(Widget w,
		  XmTextPosition position,
		  char *value)
{
  _XmWidgetToAppContext(w);

  _XmAppLock(app);
  /* XmTextFieldReplace takes care of converting to wchar_t* if needed */
  XmTextFieldReplace(w, position, position, value);
  _XmAppUnlock(app);
}

void 
XmTextFieldInsertWcs(Widget w,
		     XmTextPosition position,
		     wchar_t *wcstring)
{
  _XmWidgetToAppContext(w);

  _XmAppLock(app);
  /* XmTextFieldReplaceWcs takes care of converting to wchar_t* if needed */
  XmTextFieldReplaceWcs(w, position, position, wcstring);
  _XmAppUnlock(app);
}

void 
XmTextFieldSetAddMode(Widget w,
#if NeedWidePrototypes
		      int state)
#else
                      Boolean state)
#endif /* NeedWidePrototypes */
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  _XmWidgetToAppContext(w);
 
  _XmAppLock(app);
  if (tf->text.add_mode == state) {
    _XmAppUnlock(app);
    return;
  }
  
  _XmTextFieldDrawInsertionPoint(tf, False);
  tf->text.add_mode = state;
  _XmTextFieldDrawInsertionPoint(tf, True);
  _XmAppUnlock(app);
}

Boolean 
XmTextFieldGetAddMode(Widget w)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  Boolean ret_val;
  _XmWidgetToAppContext(w);
  
  _XmAppLock(app); 
  ret_val = tf->text.add_mode;
  _XmAppUnlock(app);
  return ret_val;
}

Boolean 
XmTextFieldGetEditable(Widget w)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  Boolean ret_val;
  _XmWidgetToAppContext(w);

  _XmAppLock(app); 
  ret_val = TextF_Editable(tf);
  _XmAppUnlock(app);
  return ret_val;
}

void 
XmTextFieldSetEditable(Widget w,
#if NeedWidePrototypes
		       int editable)
#else
                       Boolean editable)
#endif /* NeedWidePrototypes */
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  XPoint xmim_point;
  XRectangle xmim_area;
  Arg args[11];                 /* To set initial values to input method */
  XIMCallback xim_cb[5];        /* on the spot im callbacks */
  Cardinal n = 0;
  _XmWidgetToAppContext(w);

  _XmAppLock(app); 
  /* if widget previously wasn't editable, no input method has yet been
   * registered.  So, if we're making it editable now, register the IM and
   * give the IM the relevent values. */
  
  if (!TextF_Editable(tf) && editable) { 
    XmImRegister((Widget)tf, (unsigned int) NULL);
    
    GetXYFromPos(tf, TextF_CursorPosition(tf), &xmim_point.x, 
		 &xmim_point.y);
    (void)TextFieldGetDisplayRect((Widget)tf, &xmim_area);
    n = 0;
    XtSetArg(args[n], XmNfontList, TextF_FontList(tf)); n++;
    XtSetArg(args[n], XmNbackground, tf->core.background_pixel); n++;
    XtSetArg(args[n], XmNforeground, tf->primitive.foreground); n++;
    XtSetArg(args[n], XmNbackgroundPixmap,tf->core.background_pixmap);n++;
    XtSetArg(args[n], XmNspotLocation, &xmim_point); n++;
    XtSetArg(args[n], XmNarea, &xmim_area); n++;
    XtSetArg(args[n], XmNlineSpace,
	     TextF_FontAscent(tf)+ TextF_FontDescent(tf)); n++;

    /*
     * On the spot support. Register preedit callbacks.
     */
    xim_cb[0].client_data = (XPointer)tf;
    xim_cb[0].callback = (XIMProc)PreeditStart;
    xim_cb[1].client_data = (XPointer)tf;
    xim_cb[1].callback = (XIMProc)PreeditDone;
    xim_cb[2].client_data = (XPointer)tf;
    xim_cb[2].callback = (XIMProc)PreeditDraw;
    xim_cb[3].client_data = (XPointer)tf;
    xim_cb[3].callback = (XIMProc)PreeditCaret;
    XtSetArg(args[n], XmNpreeditStartCallback, &xim_cb[0]); n++;
    XtSetArg(args[n], XmNpreeditDoneCallback, &xim_cb[1]); n++;
    XtSetArg(args[n], XmNpreeditDrawCallback, &xim_cb[2]); n++;
    XtSetArg(args[n], XmNpreeditCaretCallback, &xim_cb[3]); n++;

    if (tf->text.has_focus)
       XmImSetFocusValues((Widget)tf, args, n);
    else
       XmImSetValues((Widget)tf, args, n);

  } else if (TextF_Editable(tf) && !editable) {
    XmImUnregister(w);
  }
  
  TextF_Editable(tf) = editable;
  
  n = 0;
  if (editable) {
    XtSetArg(args[n], XmNdropSiteActivity, XmDROP_SITE_ACTIVE); n++;
  } else {
    XtSetArg(args[n], XmNdropSiteActivity, XmDROP_SITE_INACTIVE); n++;
  }
  
  XmDropSiteUpdate((Widget)tf, args, n);
  _XmAppUnlock(app);
}

int 
XmTextFieldGetMaxLength(Widget w)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  int ret_val;
  _XmWidgetToAppContext(w);
  
  _XmAppLock(app);
  ret_val = TextF_MaxLength(tf);
  _XmAppUnlock(app);
  return ret_val;
}

void 
XmTextFieldSetMaxLength(Widget w,
			int max_length)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  _XmWidgetToAppContext(w);
  
  _XmAppLock(app);
  TextF_MaxLength(tf) = max_length;
  _XmAppUnlock(app);
}

XmTextPosition 
XmTextFieldGetInsertionPosition(Widget w)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  XmTextPosition ret_val;
  _XmWidgetToAppContext(w);
  
  _XmAppLock(app);
  ret_val = TextF_CursorPosition(tf);
  _XmAppUnlock(app);
  return ret_val;
}

void 
XmTextFieldSetInsertionPosition(Widget w,
				XmTextPosition position)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  _XmWidgetToAppContext(w);

  _XmAppLock(app);
  TextFieldResetIC(w);
  SetCursorPosition(tf, NULL, position, True, True, False, DontCare);
  _XmAppUnlock(app);
}

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

  _XmAppLock(app);
  
  if (tf->text.has_primary) {
    *left = tf->text.prim_pos_left;
    *right = tf->text.prim_pos_right;
  }
  _XmAppUnlock(app);
  return tf->text.has_primary;





}

char * 
XmTextFieldGetSelection(Widget w)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  size_t length, num_chars;
  char *value;
  _XmWidgetToAppContext(w);

  _XmAppLock(app);
  
  if (tf->text.prim_pos_left == tf->text.prim_pos_right) {
    _XmAppUnlock(app);
    return NULL;
  }
  num_chars = (size_t) (tf->text.prim_pos_right - tf->text.prim_pos_left);
  length = num_chars;
  if (tf->text.max_char_size == 1) {
    value = XtMalloc((unsigned) num_chars + 1);
    (void) memcpy((void*)value, 
		  (void*)(TextF_Value(tf) + tf->text.prim_pos_left), 
		  num_chars);
  } else {
    value = XtMalloc((unsigned) ((num_chars + 1) * tf->text.max_char_size));
    length = wcstombs(value, TextF_WcValue(tf) + tf->text.prim_pos_left, 
		      (num_chars + 1) * tf->text.max_char_size);
    if (length == (size_t) -1) {
      length = 0;
    } else {
      for(length = 0;num_chars > 0; num_chars--)
#ifndef NO_MULTIBYTE
	length += mblen(&value[length], tf->text.max_char_size);
#else
        length += value[length] ? 1 : 0;
#endif
    }
  }
  value[length] = (char)'\0';
  _XmAppUnlock(app);
  return (value);
}

wchar_t *
XmTextFieldGetSelectionWcs(Widget w)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  size_t length;
  wchar_t *wc_value;
  int return_val = 0;
  _XmWidgetToAppContext(w);

  _XmAppLock(app);
  if (tf->text.prim_pos_left == tf->text.prim_pos_right)
  {
    _XmAppUnlock(app);
    return NULL;
  }
  length = (size_t) (tf->text.prim_pos_right - tf->text.prim_pos_left);
  
  wc_value = (wchar_t*)XtMalloc((unsigned) (length + 1) * sizeof(wchar_t));
  
  if (tf->text.max_char_size == 1) {
    return_val = mbstowcs(wc_value, TextF_Value(tf) + tf->text.prim_pos_left, 
			  length);
    if (return_val < 0) length = 0;
  } else {
    (void)memcpy((void*)wc_value, 
		 (void*)(TextF_WcValue(tf) + tf->text.prim_pos_left), 
		 length * sizeof(wchar_t));
  }
  wc_value[length] = (wchar_t)0L;
  _XmAppUnlock(app);
  return (wc_value);
}


Boolean 
XmTextFieldRemove(Widget w)
{
  Boolean ret_val;
  _XmWidgetToAppContext(w);
 
  _XmAppLock(app);
  ret_val = TextFieldRemove(w, NULL);
  _XmAppUnlock(app);

  return ret_val;
}

Boolean 
XmTextFieldCopy(Widget w,
		Time clip_time)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  _XmWidgetToAppContext(w);
 
  _XmAppLock(app);
  /* using the clipboard facilities, copy the selected 
     text to the clipboard */
  if (tf->text.prim_pos_left != tf->text.prim_pos_right)
  {
    _XmAppUnlock(app);
    return XmeClipboardSource(w, XmCOPY, clip_time);
  }

  _XmAppUnlock(app);
  return False;
}

Boolean 
XmTextFieldCopyLink(Widget w,
		    Time clip_time)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  Boolean ret_val;
  _XmWidgetToAppContext(w);
 
  _XmAppLock(app);
  if (tf->text.prim_pos_left != tf->text.prim_pos_right)
  {
    ret_val = XmeClipboardSource(w, XmLINK, clip_time);
    _XmAppUnlock(app);
    return ret_val;
  }

  _XmAppUnlock(app);
  return False;
}

Boolean 
XmTextFieldCut(Widget w,
	       Time clip_time)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  Boolean ret_val;
  _XmWidgetToAppContext(w);
 
  _XmAppLock(app);
  
  if (TextF_Editable(tf) == False)
  {
    _XmAppUnlock(app);
    return False;
  }
  
  if (tf->text.prim_pos_left != tf->text.prim_pos_right)
  {
    ret_val = XmeClipboardSource(w, XmMOVE, clip_time);
    _XmAppUnlock(app);
    return ret_val;
  }

  _XmAppUnlock(app);
  return False;

}

void 
XmTextFieldClearSelection(Widget w,
			  Time sel_time)
{
  _XmWidgetToAppContext(w);
 
  _XmAppLock(app);
  _XmTextFieldDeselectSelection(w, False, sel_time);
  _XmAppUnlock(app);
}

void 
XmTextFieldSetSelection(Widget w,
			XmTextPosition first,
			XmTextPosition last,
			Time sel_time)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  _XmWidgetToAppContext(w);
 
  _XmAppLock(app);
  TextFieldResetIC(w);
  tf->text.take_primary = True;
  _XmTextFieldStartSelection(tf, first, last, sel_time);
  tf->text.pending_off = False;
  SetCursorPosition(tf, NULL, last, True, True, False, DontCare);
  _XmAppUnlock(app);
}

/* ARGSUSED */
XmTextPosition 
XmTextFieldXYToPos(Widget w,
#if NeedWidePrototypes
		   int x,
		   int y)
#else
                   Position x,
                   Position y)
#endif /* NeedWidePrototypes */
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  XmTextPosition ret_val;
  _XmWidgetToAppContext(w);
  
  _XmAppLock(app);
  ret_val = GetPosFromX(tf, x);
  _XmAppUnlock(app);
  return (ret_val);
}

Boolean 
XmTextFieldPosToXY(Widget w,
		   XmTextPosition position,
		   Position *x,
		   Position *y)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  Boolean ret_val;
  _XmWidgetToAppContext(w);
 
  _XmAppLock(app);
  ret_val = GetXYFromPos(tf, position, x, y);
  _XmAppUnlock(app);
  return (ret_val);
}


/*
 * Force the given position to be displayed.  If position is out of bounds, 
 * then don't force any position to be displayed.
 */
void 
XmTextFieldShowPosition(Widget w,
			XmTextPosition position)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  _XmWidgetToAppContext(w);
 
  _XmAppLock(app);
  if ( (position < 0) || (position > tf->text.string_length) ) {
	_XmAppUnlock(app);
	return;
  }
  
  AdjustText(tf, position, True);
  _XmAppUnlock(app);
}

/* ARGSUSED */
void 
XmTextFieldSetHighlight(Widget w,
			XmTextPosition left,
			XmTextPosition right,
			XmHighlightMode mode)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  _XmWidgetToAppContext(w);

  _XmAppLock(app);
  doSetHighlight(w, left, right, mode);
  tf->text.programmatic_highlights = True;
  _XmAppUnlock(app);
}

static Boolean
TrimHighlights(XmTextFieldWidget tf, int *low, int *high)
{
 	/* 
 	** We have a situation in which the programmer has called 
 	** XmTextFieldSetHighlight and the user is now interacting with the
 	** text, which has the possible effect of mis-inserting and doing all
 	** sorts of nasty stuff, mostly because this widget assumes that such
 	** settings are ephemeral and last only as long as user interaction.
 	** As programmer-defined highlights are assumed to be reasonable only
 	** for e.g. non-editable text areas, reset them.
 	*/
 
	Boolean changed = False;
 	Boolean justChanged = False;
 	_XmHighlightRec *l = tf->text.highlight.list;
 	int i;
 
 	for (i=0; i < tf->text.highlight.number; i++)
 	{
 		/* iterate through list, resetting spurious back to normal;
 		** unfortunately, we can have has_primary even when there is
 		** no primary selection anymore, so check pending-deleteness
 		*/ 
 		if (justChanged)
 			*high = l[i].position; 
 		if (((XmHIGHLIGHT_SECONDARY_SELECTED == l[i].mode) && !tf->text.has_secondary)
 		  ||((XmHIGHLIGHT_SELECTED == l[i].mode) && !NeedsPendingDelete(tf)))
 			{
 			l[i].mode = XmHIGHLIGHT_NORMAL;
 			if (!changed)
 				*low = l[i].position;
 			changed = True;
 			justChanged = True;
 			}
 		else
 			justChanged = False;
 	}
 	if (justChanged)
 		*high = tf->text.string_length;
 
 	if (changed)
 	{
  	  int j;
 	  /* coalescing blocks; reduce number only */
 	  i = 1;
 	  while (i < tf->text.highlight.number) {
 	    if (l[i].mode == l[i-1].mode) {
 	      tf->text.highlight.number--;
 	      for (j=i; j<tf->text.highlight.number; j++)
 		l[j] = l[j+1];
 	    } else i++;
 	  }
 	}
 
 	return changed;
}

/* ARGSUSED */
static void
doSetHighlight(Widget w, XmTextPosition left, XmTextPosition right,
			XmHighlightMode mode)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;

  /* If right position is out-bound, change it to the last position. */
  if (right > tf->text.string_length)
    right = tf->text.string_length;

  /* If left is out-bound, don't do anything. */
  if (left >= right || right <= 0) {
     return;
  }
 
  if (left < 0) left = 0;
 
  TextFieldSetHighlight(tf, left, right, mode);

  RedisplayText(tf, left, right);
}

int 
XmTextFieldGetBaseline(Widget w)
{
  XmTextFieldWidget tf = (XmTextFieldWidget) w;
  Dimension margin_top;
  int ret_val;
  _XmWidgetToAppContext(w);

  _XmAppLock(app);
  margin_top = tf->text.margin_top +
    tf->primitive.shadow_thickness +
      tf->primitive.highlight_thickness;
  
  ret_val = (int) margin_top + (int) TextF_FontAscent(tf);
  _XmAppUnlock(app);

  return(ret_val);
}

/*
 * Text Field w creation convienence routine.
 */

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

/****************************************************************/
/****************************************************************/
