text: /* $Xorg: TextAction.c,v 1.4 2001/02/09 02:03:46 xorgcvs Exp $ */
  
  /*
  
  Copyright 1989, 1994, 1998  The Open Group
  
  Permission to use, copy, modify, distribute, and sell this software and its
  documentation for any purpose is hereby granted without fee, provided that
  the above copyright notice appear in all copies and that both that
  copyright notice and this permission notice appear in supporting
  documentation.
  
  The above copyright notice and this permission notice shall be included in
  all copies or substantial portions of the Software.
  
  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
  OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
  AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  
  Except as contained in this notice, the name of The Open Group shall not be
  used in advertising or otherwise to promote the sale, use or other dealings
  in this Software without prior written authorization from The Open Group.
  
  */
  /* $XFree86: xc/lib/Xaw/TextAction.c,v 3.46tsi Exp $ */
  
  #ifdef HAVE_CONFIG_H
  #include <config.h>
  #endif
  #include <stdio.h>
  #include <stdlib.h>
  #include <X11/Xos.h>		/* for select() and struct timeval */
  #include <ctype.h>
  #include <X11/IntrinsicP.h>
  #include <X11/StringDefs.h>
  #include <X11/Xatom.h>
  #include <X11/Xfuncs.h>
  #include <X11/Xutil.h>
  #include <X11/Xmu/Atoms.h>
  #include <X11/Xmu/Misc.h>
  #include <X11/Xmu/StdSel.h>
  #include <X11/Xmu/SysUtil.h>
  #include <X11/Xaw/MultiSinkP.h>
  #include <X11/Xaw/MultiSrcP.h>
  #include <X11/Xaw/TextP.h>
  #include <X11/Xaw/TextSrcP.h>
  #include <X11/Xaw/XawImP.h>
  #include "Private.h"
  #include "XawI18n.h"
  
  #define SrcScan			XawTextSourceScan
  #define FindDist		XawTextSinkFindDistance
  #define FindPos			XawTextSinkFindPosition
  #define MULT(w)			(w->text.mult == 0 ? 4 :		\
  				 w->text.mult == 32767 ? -4 : w->text.mult)
  
  #define KILL_RING_APPEND	2
  #define KILL_RING_BEGIN		3
  #define KILL_RING_YANK		100
  #define KILL_RING_YANK_DONE	98
  
  #define XawTextActionMaxHexChars	100
  
  /*
   * Prototypes
   */
  static void _DeleteOrKill(TextWidget, XawTextPosition, XawTextPosition, Bool);
  static void _SelectionReceived(Widget, XtPointer, Atom*, Atom*, XtPointer,
  			       unsigned long*, int*);
  static void _LoseSelection(Widget, Atom*, char**, int*);
  static void AutoFill(TextWidget);
  static Boolean ConvertSelection(Widget, Atom*, Atom*, Atom*, XtPointer*,
  				unsigned long*, int*);
  static void DeleteOrKill(TextWidget, XEvent*, XawTextScanDirection,
  			 XawTextScanType, Bool, Bool);
  static void EndAction(TextWidget);
  #ifndef OLDXAW
  static Bool BlankLine(Widget, XawTextPosition, int*);
  static int DoFormatText(TextWidget, XawTextPosition, Bool, int,
  			XawTextBlock*, XawTextPosition*, int, Bool);
  static int FormatText(TextWidget, XawTextPosition, Bool,
  		      XawTextPosition*, int);
  static Bool GetBlockBoundaries(TextWidget, XawTextPosition*, XawTextPosition*);
  #endif
  static int FormRegion(TextWidget, XawTextPosition, XawTextPosition,
  		      XawTextPosition*, int);
  static void GetSelection(Widget, Time, String*, Cardinal);
  static char *IfHexConvertHexElseReturnParam(char*, int*);
  static void InsertNewCRs(TextWidget, XawTextPosition, XawTextPosition,
  			 XawTextPosition*, int);
  static int InsertNewLineAndBackupInternal(TextWidget);
  static int LocalInsertNewLine(TextWidget, XEvent*);
  static void LoseSelection(Widget, Atom*);
  static void ParameterError(Widget, String);
  static Bool MatchSelection(Atom, XawTextSelection*);
  static void ModifySelection(TextWidget, XEvent*, XawTextSelectionMode,
  			    XawTextSelectionAction, String*, Cardinal*);
  static void Move(TextWidget, XEvent*, XawTextScanDirection, XawTextScanType,
  		 Bool);
  static void NotePosition(TextWidget, XEvent*);
  static void StartAction(TextWidget, XEvent*);
  static XawTextPosition StripOutOldCRs(TextWidget, XawTextPosition,
  				      XawTextPosition, XawTextPosition*, int);
  #ifndef OLDXAW
  static Bool StripSpaces(TextWidget, XawTextPosition, XawTextPosition,
  			XawTextPosition*, int, XawTextBlock*);
  static Bool Tabify(TextWidget, XawTextPosition, XawTextPosition,
  		   XawTextPosition*, int, XawTextBlock*);
  static Bool Untabify(TextWidget, XawTextPosition, XawTextPosition,
  		     XawTextPosition*, int, XawTextBlock*);
  #endif
  
  /*
   * Actions
   */
  static void CapitalizeWord(Widget, XEvent*, String*, Cardinal*);
  static void DisplayCaret(Widget, XEvent*, String*, Cardinal*);
  static void Delete(Widget, XEvent*, String*, Cardinal*);
  static void DeleteBackwardChar(Widget, XEvent*, String*, Cardinal*);
  static void DeleteBackwardWord(Widget, XEvent*, String*, Cardinal*);
  static void DeleteCurrentSelection(Widget, XEvent*, String*, Cardinal*);
  static void DeleteForwardChar(Widget, XEvent*, String*, Cardinal*);
  static void DeleteForwardWord(Widget, XEvent*, String*, Cardinal*);
  static void DowncaseWord(Widget, XEvent*, String*, Cardinal*);
  static void ExtendAdjust(Widget, XEvent*, String*, Cardinal*);
  static void ExtendEnd(Widget, XEvent*, String*, Cardinal*);
  static void ExtendStart(Widget, XEvent*, String*, Cardinal*);
  static void FormParagraph(Widget, XEvent*, String*, Cardinal*);
  #ifndef OLDXAW
  static void Indent(Widget, XEvent*, String*, Cardinal*);
  #endif
  static void InsertChar(Widget, XEvent*, String*, Cardinal*);
  static void InsertNewLine(Widget, XEvent*, String*, Cardinal*);
  static void InsertNewLineAndBackup(Widget, XEvent*, String*, Cardinal*);
  static void InsertNewLineAndIndent(Widget, XEvent*, String*, Cardinal*);
  static void InsertSelection(Widget, XEvent*, String*, Cardinal*);
  static void InsertString(Widget, XEvent*, String*, Cardinal*);
  #ifndef OLDXAW
  static void KeyboardReset(Widget, XEvent*, String*, Cardinal*);
  #endif
  static void KillBackwardWord(Widget, XEvent*, String*, Cardinal*);
  static void KillCurrentSelection(Widget, XEvent*, String*, Cardinal*);
  static void KillForwardWord(Widget, XEvent*, String*, Cardinal*);
  #ifndef OLDXAW
  static void KillRingYank(Widget, XEvent*, String*, Cardinal*);
  #endif
  static void KillToEndOfLine(Widget, XEvent*, String*, Cardinal*);
  static void KillToEndOfParagraph(Widget, XEvent*, String*, Cardinal*);
  static void MoveBackwardChar(Widget, XEvent*, String*, Cardinal*);
  static void MoveBackwardWord(Widget, XEvent*, String*, Cardinal*);
  static void MoveBackwardParagraph(Widget, XEvent*, String*, Cardinal*);
  static void MoveBeginningOfFile(Widget, XEvent*, String*, Cardinal*);
  static void MoveEndOfFile(Widget, XEvent*, String*, Cardinal*);
  static void MoveForwardChar(Widget, XEvent*, String*, Cardinal*);
  static void MoveForwardWord(Widget, XEvent*, String*, Cardinal*);
  static void MoveForwardParagraph(Widget, XEvent*, String*, Cardinal*);
  static void MoveNextLine(Widget, XEvent*, String*, Cardinal*);
  static void MoveNextPage(Widget, XEvent*, String*, Cardinal*);
  static void MovePage(TextWidget, XEvent*, XawTextScanDirection);
  static void MovePreviousLine(Widget, XEvent*, String*, Cardinal*);
  static void MovePreviousPage(Widget, XEvent*, String*, Cardinal*);
  static void MoveLine(TextWidget, XEvent*, XawTextScanDirection);
  static void MoveToLineEnd(Widget, XEvent*, String*, Cardinal*);
  static void MoveToLineStart(Widget, XEvent*, String*, Cardinal*);
  static void Multiply(Widget, XEvent*, String*, Cardinal*);
  static void NoOp(Widget, XEvent*, String*, Cardinal*);
  #ifndef OLDXAW
  static void Numeric(Widget, XEvent*, String*, Cardinal*);
  #endif
  static void Reconnect(Widget, XEvent*, String*, Cardinal*);
  static void RedrawDisplay(Widget, XEvent*, String*, Cardinal*);
  static void Scroll(TextWidget, XEvent*, XawTextScanDirection);
  static void ScrollOneLineDown(Widget, XEvent*, String*, Cardinal*);
  static void ScrollOneLineUp(Widget, XEvent*, String*, Cardinal*);
  static void SelectAdjust(Widget, XEvent*, String*, Cardinal*);
  static void SelectAll(Widget, XEvent*, String*, Cardinal*);
  static void SelectEnd(Widget, XEvent*, String*, Cardinal*);
  static void SelectSave(Widget, XEvent*, String*, Cardinal*);
  static void SelectStart(Widget, XEvent*, String*, Cardinal*);
  static void SelectWord(Widget, XEvent*, String*, Cardinal*);
  static void SetKeyboardFocus(Widget, XEvent*, String*, Cardinal*);
  static void TextEnterWindow(Widget, XEvent*, String*, Cardinal*);
  static void TextFocusIn(Widget, XEvent*, String*, Cardinal*);
  static void TextFocusOut(Widget, XEvent*, String*, Cardinal*);
  static void TextLeaveWindow(Widget, XEvent*, String*, Cardinal*);
  static void TransposeCharacters(Widget, XEvent*, String*, Cardinal*);
  #ifndef OLDXAW
  static void ToggleOverwrite(Widget, XEvent*, String*, Cardinal*);
  static void Undo(Widget, XEvent*, String*, Cardinal*);
  #endif
  static void UpcaseWord(Widget, XEvent*, String*, Cardinal*);
  static void DestroyFocusCallback(Widget, XtPointer, XtPointer);
  
  /*
   * External
   */
  void _XawTextZapSelection(TextWidget, XEvent*, Bool);
  
  /*
   * Defined in TextPop.c
   */
  void _XawTextInsertFileAction(Widget, XEvent*, String*, Cardinal*);
  void _XawTextInsertFile(Widget, XEvent*, String*, Cardinal*);
  void _XawTextSearch(Widget, XEvent*, String*, Cardinal*);
  void _XawTextDoSearchAction(Widget, XEvent*, String*, Cardinal*);
  void _XawTextDoReplaceAction(Widget, XEvent*, String*, Cardinal*);
  void _XawTextSetField(Widget, XEvent*, String*, Cardinal*);
  void _XawTextPopdownSearchAction(Widget, XEvent*, String*, Cardinal*);
  
  /*
   * These are defined in Text.c
   */
  void _XawTextAlterSelection(TextWidget, XawTextSelectionMode,
  			    XawTextSelectionAction, String*, Cardinal*);
  void _XawTextClearAndCenterDisplay(TextWidget);
  void _XawTextExecuteUpdate(TextWidget);
  char *_XawTextGetText(TextWidget, XawTextPosition, XawTextPosition);
  void _XawTextPrepareToUpdate(TextWidget);
  int _XawTextReplace(TextWidget, XawTextPosition, XawTextPosition,
  			   XawTextBlock*);
  Atom *_XawTextSelectionList(TextWidget, String*, Cardinal);
  void _XawTextSetSelection(TextWidget, XawTextPosition, XawTextPosition,
  				 String*, Cardinal);
  void _XawTextVScroll(TextWidget, int);
  void XawTextScroll(TextWidget, int, int);
  void _XawTextSetLineAndColumnNumber(TextWidget, Bool);
  
  #ifndef OLDXAW
  /*
   * Defined in TextSrc.c
   */
  Bool _XawTextSrcUndo(TextSrcObject, XawTextPosition*);
  Bool _XawTextSrcToggleUndo(TextSrcObject);
  void _XawSourceSetUndoErase(TextSrcObject, int);
  void _XawSourceSetUndoMerge(TextSrcObject, Bool);
  #endif /* OLDXAW */
  
  /*
   * Initialization
   */
  #ifndef OLDXAW
  #define MAX_KILL_RINGS	1024
  XawTextKillRing *xaw_text_kill_ring;
  static XawTextKillRing kill_ring_prev, kill_ring_null = { &kill_ring_prev, };
  static unsigned num_kill_rings;
  #endif
  
  /*
   * Implementation
   */
  static void
  ParameterError(Widget w, String param)
  {
      String params[2];
      Cardinal num_params = 2;
      params[0] = XtName(w);
      params[1] = param;
  
      XtAppWarningMsg(XtWidgetToApplicationContext(w),
  		    "parameterError", "textAction", "XawError",
  		    "Widget: %s Parameter: %s",
  		    params, &num_params);
      XBell(XtDisplay(w), 50);
  }
  
  static void
  StartAction(TextWidget ctx, XEvent *event)
  {
  #ifndef OLDXAW
      Cardinal i;
      TextSrcObject src = (TextSrcObject)ctx->text.source;
  
      for (i = 0; i < src->textSrc.num_text; i++)
  	_XawTextPrepareToUpdate((TextWidget)src->textSrc.text[i]);
      _XawSourceSetUndoMerge(src, False);
  #else
      _XawTextPrepareToUpdate(ctx);
  #endif
  
      if (event != NULL) {
  	switch (event->type) {
  	    case ButtonPress:
  	    case ButtonRelease:
  		ctx->text.time = event->xbutton.time;
  		break;
  	    case KeyPress:
  	    case KeyRelease:
  		ctx->text.time = event->xkey.time;
  		break;
  	    case MotionNotify:
  		ctx->text.time = event->xmotion.time;
  		break;
  	    case EnterNotify:
  	    case LeaveNotify:
  		ctx->text.time = event->xcrossing.time;
  	}
      }
  }
  
  static void
  NotePosition(TextWidget ctx, XEvent *event)
  {
      switch (event->type) {
  	case ButtonPress:
  	case ButtonRelease:
  	    ctx->text.ev_x = event->xbutton.x;
  	    ctx->text.ev_y = event->xbutton.y;
  	    break;
  	case KeyPress:
  	case KeyRelease: {
  	    XRectangle cursor;
  	    XawTextSinkGetCursorBounds(ctx->text.sink, &cursor);
  	    ctx->text.ev_x = cursor.x + cursor.width / 2;
  	    ctx->text.ev_y = cursor.y + cursor.height / 2;
  	}   break;
  	case MotionNotify:
  	    ctx->text.ev_x = event->xmotion.x;
  	    ctx->text.ev_y = event->xmotion.y;
  	    break;
  	case EnterNotify:
  	case LeaveNotify:
  	    ctx->text.ev_x = event->xcrossing.x;
  	    ctx->text.ev_y = event->xcrossing.y;
      }
  }
  
  static void
  EndAction(TextWidget ctx)
  {
  #ifndef OLDXAW
      Cardinal i;
      TextSrcObject src = (TextSrcObject)ctx->text.source;
  
      for (i = 0; i < src->textSrc.num_text; i++)
  	_XawTextExecuteUpdate((TextWidget)src->textSrc.text[i]);
  
      ctx->text.mult = 1;
      ctx->text.numeric = False;
      if (ctx->text.kill_ring) {
  	if (--ctx->text.kill_ring == KILL_RING_YANK_DONE) {
  	    if (ctx->text.kill_ring_ptr) {
  		--ctx->text.kill_ring_ptr->refcount;
  		ctx->text.kill_ring_ptr = NULL;
  	    }
  	}
      }
  #else
      ctx->text.mult = 1;
      _XawTextExecuteUpdate(ctx);
  #endif /* OLDXAW */
  }
  
  struct _SelectionList {
      String* params;
      Cardinal count;
      Time time;
      int asked;		/* which selection currently has been asked for:
  			   0 = UTF8_STRING, 1 = COMPOUND_TEXT, 2 = STRING */
      Atom selection;	/* selection atom (normally XA_PRIMARY) */
  };
  
  /*ARGSUSED*/
  static void
  _SelectionReceived(Widget w, XtPointer client_data, Atom *selection,
  		   Atom *type, XtPointer value, unsigned long *length,
  		   int *format)
  {
      Display *d = XtDisplay(w);
      TextWidget ctx = (TextWidget)w;
      XawTextBlock text;
  
      if (*type == 0 /*XT_CONVERT_FAIL*/ || *length == 0) {
  	struct _SelectionList* list = (struct _SelectionList*)client_data;
  
  	if (list != NULL) {
  	    if (list->asked == 0) {
  		/* If we just asked for XA_UTF8_STRING and got no response,
  		   we'll ask again, this time for XA_COMPOUND_TEXT. */
  		list->asked++;
  		XtGetSelectionValue(w, list->selection, XA_COMPOUND_TEXT(d),
  				    _SelectionReceived,
  				    (XtPointer)list, list->time);
  	    } else if (list->asked == 1) {
  		/* If we just asked for XA_COMPOUND_TEXT and got no response,
  		   we'll ask again, this time for XA_STRING. */
  		list->asked++;
  		XtGetSelectionValue(w, list->selection, XA_STRING,
  				    _SelectionReceived,
  				    (XtPointer)list, list->time);
  	    } else {
  		/* We tried all possible text targets in this param.
  		   Recurse on the tail of the params list. */
  		GetSelection(w, list->time, list->params, list->count);
  		XtFree(client_data);
  	    }
  	}
  	return;
      }
  
      StartAction(ctx, NULL);
      if (XawTextFormat(ctx, XawFmtWide)) {
  	XTextProperty textprop;
  	wchar_t **wlist;
  	int count;
  
  	textprop.encoding = *type;
  	textprop.value = (unsigned char *)value;
  	textprop.nitems = strlen(value);
  	textprop.format = 8;
  
  	if (XwcTextPropertyToTextList(d, &textprop, &wlist, &count)
  	    !=	Success
  	    || count < 1) {
  	    XwcFreeStringList(wlist);
  
  	    /* Notify the user on strerr and in the insertion :) */
  	    fprintf(stderr, "Xaw Text Widget: An attempt was made to insert "
  		    "an illegal selection.\n");
  
  	    textprop.value = (unsigned char *)" >> ILLEGAL SELECTION << ";
  	    textprop.nitems = strlen((char *) textprop.value);
  	    if (XwcTextPropertyToTextList(d, &textprop, &wlist, &count)
  		!=  Success
  		|| count < 1)
  		return;
  	}
  
  	XFree(value);
  	value = (XPointer)wlist[0];
  
  	*length = wcslen(wlist[0]);
  	XtFree((XtPointer)wlist);
  	text.format = XawFmtWide;
      }
      text.ptr = (char*)value;
      text.firstPos = 0;
      text.length = *length;
      if (_XawTextReplace(ctx, ctx->text.insertPos, ctx->text.insertPos, &text)) {
  	XBell(XtDisplay(ctx), 0);
  	EndAction(ctx);
  	return;
      }
  
      ctx->text.from_left = -1;
      ctx->text.insertPos = SrcScan(ctx->text.source, ctx->text.old_insert,
  				  XawstPositions, XawsdRight, text.length, True);
  
      EndAction(ctx);
      XtFree(client_data);
      XFree(value);	/* the selection value should be freed with XFree */
  }
  
  static void
  GetSelection(Widget w, Time timev, String *params, Cardinal num_params)
  {
      Display *d = XtDisplay(w);
      TextWidget ctx = (TextWidget)w;
      Atom selection;
      int buffer;
  
      selection = XInternAtom(XtDisplay(w), *params, False);
      switch (selection) {
  	case XA_CUT_BUFFER0: buffer = 0; break;
  	case XA_CUT_BUFFER1: buffer = 1; break;
  	case XA_CUT_BUFFER2: buffer = 2; break;
  	case XA_CUT_BUFFER3: buffer = 3; break;
  	case XA_CUT_BUFFER4: buffer = 4; break;
  	case XA_CUT_BUFFER5: buffer = 5; break;
  	case XA_CUT_BUFFER6: buffer = 6; break;
  	case XA_CUT_BUFFER7: buffer = 7; break;
  	default:	     buffer = -1;
      }
      if (buffer >= 0) {
  	int nbytes;
  	unsigned long length;
  	int fmt8 = 8;
  	Atom type = XA_STRING;
  	char *line = XFetchBuffer(XtDisplay(w), &nbytes, buffer);
  
  	if ((length = nbytes) != 0L)
  	    _SelectionReceived(w, NULL, &selection, &type, line, &length, &fmt8);
  	else if (num_params > 1)
  	    GetSelection(w, timev, params+1, num_params-1);
      }
      else {
  	struct _SelectionList* list;
  
  	if (--num_params) {
  	    list = XtNew(struct _SelectionList);
  	    list->params = params + 1;
  	    list->count = num_params;
  	    list->time = timev;
  	    list->asked = 0;
  	    list->selection = selection;
  	}
  	else
  	    list = NULL;
  	XtGetSelectionValue(w, selection, XawTextFormat(ctx, XawFmtWide) ?
  			    XA_UTF8_STRING(d) : XA_TEXT(d),
  			    _SelectionReceived, (XtPointer)list, timev);
      }
  }
  
  static void
  InsertSelection(Widget w, XEvent *event, String *params, Cardinal *num_params)
  {
      StartAction((TextWidget)w, event);	/* Get Time. */
      GetSelection(w, ((TextWidget)w)->text.time, params, *num_params);
      EndAction((TextWidget)w);
  }
  
  /*
   * Routines for Moving Around
   */
  static void
  Move(TextWidget ctx, XEvent *event, XawTextScanDirection dir,
       XawTextScanType type, Bool include)
  {
      XawTextPosition insertPos;
      short mult = MULT(ctx);
  
      if (mult < 0) {
  	mult = -mult;
  	dir = dir == XawsdLeft ? XawsdRight : XawsdLeft;
      }
  
      insertPos = SrcScan(ctx->text.source, ctx->text.insertPos,
  			type, dir, mult, include);
  
      StartAction(ctx, event);
  
      if (ctx->text.s.left != ctx->text.s.right)
  	XawTextUnsetSelection((Widget)ctx);
  
  #ifndef OLDXAW
      ctx->text.numeric = False;
  #endif
      ctx->text.mult = 1;
      ctx->text.showposition = True;
      ctx->text.from_left = -1;
      ctx->text.insertPos = insertPos;
      EndAction(ctx);
  }
  
  /*ARGSUSED*/
  static void
  MoveForwardChar(Widget w, XEvent *event, String *p, Cardinal *n)
  {
      Move((TextWidget)w, event, XawsdRight, XawstPositions, True);
  }
  
  /*ARGSUSED*/
  static void
  MoveBackwardChar(Widget w, XEvent *event, String *p, Cardinal *n)
  {
      Move((TextWidget)w, event, XawsdLeft, XawstPositions, True);
  }
  
  static void
  MoveForwardWord(Widget w, XEvent *event, String *p, Cardinal *n)
  {
      if (*n && (p[0][0] == 'A' || p[0][0] == 'a'))
  	Move((TextWidget)w, event, XawsdRight, XawstAlphaNumeric, False);
      else
  	Move((TextWidget)w, event, XawsdRight, XawstWhiteSpace, False);
  }
  
  static void
  MoveBackwardWord(Widget w, XEvent *event, String *p, Cardinal *n)
  {
      if (*n && (p[0][0] == 'A' || p[0][0] == 'a'))
  	Move((TextWidget)w, event, XawsdLeft, XawstAlphaNumeric, False);
      else
  	Move((TextWidget)w, event, XawsdLeft, XawstWhiteSpace, False);
  }
  
  static void
  MoveForwardParagraph(Widget w, XEvent *event, String *p, Cardinal *n)
  {
      TextWidget ctx = (TextWidget)w;
      XawTextPosition position = ctx->text.insertPos;
      short mult = MULT(ctx);
  
      if (mult < 0) {
  	ctx->text.mult = -mult;
  	MoveBackwardParagraph(w, event, p, n);
  	return;
      }
  
      while (mult--) {
  	position = SrcScan(ctx->text.source, position,
  			   XawstEOL, XawsdRight, 1, False) - 1;
  
  	while (position == SrcScan(ctx->text.source, position,
  				   XawstEOL, XawsdRight, 1, False))
  	    if (++position > ctx->text.lastPos) {
  		mult = 0;
  		break;
  	    }
  
  	position = SrcScan(ctx->text.source, position,
  			   XawstParagraph, XawsdRight, 1, True);
  	if (position != ctx->text.lastPos)
  	    position = SrcScan(ctx->text.source, position - 1,
  			       XawstEOL, XawsdLeft, 1, False);
  	else
  	    break;
      }
  
      if (position != ctx->text.insertPos) {
  	XawTextUnsetSelection(w);
  	StartAction(ctx, event);
  	ctx->text.showposition = True;
  	ctx->text.from_left = -1;
  	ctx->text.insertPos = position;
  	EndAction(ctx);
      }
      else
  	ctx->text.mult = 1;
  }
  
  /*ARGSUSED*/
  static void
  MoveBackwardParagraph(Widget w, XEvent *event, String *p, Cardinal *n)
  {
      TextWidget ctx = (TextWidget)w;
      XawTextPosition position = ctx->text.insertPos;
      short mult = MULT(ctx);
  
      if (mult < 0) {
  	ctx->text.mult = -mult;
  	MoveForwardParagraph(w, event, p, n);
  	return;
      }
  
      while (mult--) {
  	position = SrcScan(ctx->text.source, position,
  			   XawstEOL, XawsdLeft, 1, False) + 1;
  
  	while (position == SrcScan(ctx->text.source, position,
  				   XawstEOL, XawsdLeft, 1, False))
  	    if (--position < 0) {
  		mult = 0;
  		break;
  	    }
  
  	position = SrcScan(ctx->text.source, position,
  			   XawstParagraph, XawsdLeft, 1, True);
  	if (position > 0 && position < ctx->text.lastPos)
  	    ++position;
  	else
  	    break;
      }
  
      if (position != ctx->text.insertPos) {
  	XawTextUnsetSelection(w);
  	StartAction(ctx, event);
  	ctx->text.showposition = True;
  	ctx->text.from_left = -1;
  	ctx->text.insertPos = position;
  	EndAction(ctx);
      }
      else
  	ctx->text.mult = 1;
  }
  
  /*ARGSUSED*/
  static void
  MoveToLineEnd(Widget w, XEvent *event, String *p, Cardinal *n)
  {
      Move((TextWidget)w, event, XawsdRight, XawstEOL, False);
  }
  
  /*ARGSUSED*/
  static void
  MoveToLineStart(Widget w, XEvent *event, String *p, Cardinal *n)
  {
      Move((TextWidget)w, event, XawsdLeft, XawstEOL, False);
  }
  
  static void
  MoveLine(TextWidget ctx, XEvent *event, XawTextScanDirection dir)
  {
      XawTextPosition cnew, next_line, ltemp;
      int itemp, from_left;
      short mult = MULT(ctx);
  
      StartAction(ctx, event);
  
      XawTextUnsetSelection((Widget)ctx);
  
      if (dir == XawsdLeft)
  	mult = mult == 0 ? 5 : mult + 1;
  
      cnew = SrcScan(ctx->text.source, ctx->text.insertPos,
  		   XawstEOL, XawsdLeft, 1, False);
  
      if (ctx->text.from_left < 0)
  	FindDist(ctx->text.sink, cnew, ctx->text.left_margin, ctx->text.insertPos,
  		 &ctx->text.from_left, &ltemp, &itemp);
  
      cnew = SrcScan(ctx->text.source, ctx->text.insertPos, XawstEOL, dir,
  		   mult, (dir == XawsdRight));
  
      next_line = SrcScan(ctx->text.source, cnew, XawstEOL, XawsdRight, 1, False);
  
      FindPos(ctx->text.sink, cnew, ctx->text.left_margin, ctx->text.from_left,
  	    False, &ctx->text.insertPos, &from_left, &itemp);
  
      if (from_left < ctx->text.from_left) {
  	XawTextBlock block;
  
  	XawTextSourceRead(ctx->text.source, ctx->text.insertPos, &block, 1);
  	if (block.length) {
  	    if (XawTextFormat(ctx, XawFmtWide)) {
  		if (*(wchar_t *)block.ptr == _Xaw_atowc(XawTAB))
  		    ++ctx->text.insertPos;
  	    }
  	    else if (block.ptr[0] == XawTAB)
  		++ctx->text.insertPos;
  	}
      }
  
      if (ctx->text.insertPos > next_line)
  	ctx->text.insertPos = next_line;
  
      EndAction(ctx);
  }
  
  static void
  MoveNextLine(Widget w, XEvent *event, String *p, Cardinal *n)
  {
      TextWidget ctx = (TextWidget)w;
      short mult = MULT(ctx);
  
      if (mult < 0) {
  	ctx->text.mult = -mult;
  	MovePreviousLine(w, event, p, n);
  	return;
      }
  
      if (ctx->text.insertPos < ctx->text.lastPos)
  	MoveLine(ctx, event, XawsdRight);
      else
  	ctx->text.mult = 1;
  }
  
  static void
  MovePreviousLine(Widget w, XEvent *event, String *p, Cardinal *n)
  {
      TextWidget ctx = (TextWidget)w;
      short mult = MULT(ctx);
  
      if (mult < 0) {
  	ctx->text.mult = -mult;
  	MoveNextLine(w, event, p, n);
  	return;
      }
  
      if (ctx->text.lt.top != 0 || (ctx->text.lt.lines > 1 &&
  	ctx->text.insertPos >= ctx->text.lt.info[1].position))
  	MoveLine(ctx, event, XawsdLeft);
      else
  	ctx->text.mult = 1;
  }
  
  /*ARGSUSED*/
  static void
  MoveBeginningOfFile(Widget w, XEvent *event, String *p, Cardinal *n)
  {
      Move((TextWidget)w, event, XawsdLeft, XawstAll, True);
  }
  
  /*ARGSUSED*/
  static void
  MoveEndOfFile(Widget w, XEvent *event, String *p, Cardinal *n)
  {
      Move((TextWidget)w, event, XawsdRight, XawstAll, True);
  }
  
  static void
  Scroll(TextWidget ctx, XEvent *event, XawTextScanDirection dir)
  {
      short mult = MULT(ctx);
  
      if (mult < 0) {
  	mult = -mult;
  	dir = dir == XawsdLeft ? XawsdRight : XawsdLeft;
      }
  
      if (ctx->text.lt.lines > 1
  	&& (dir == XawsdRight
  	    || ctx->text.lastPos >= ctx->text.lt.info[1].position)) {
  	StartAction(ctx, event);
  
  	if (dir == XawsdLeft)
  	    _XawTextVScroll(ctx, mult);
  	else
  	    _XawTextVScroll(ctx, -mult);
  
  	EndAction(ctx);
      }
      else {
  	ctx->text.mult = 1;
  #ifndef OLDXAW
  	ctx->text.numeric = False;
  #endif
      }
  }
  
  /*ARGSUSED*/
  static void
  ScrollOneLineUp(Widget w, XEvent *event, String *p, Cardinal *n)
  {
      Scroll((TextWidget)w, event, XawsdLeft);
  }
  
  /*ARGSUSED*/
  static void
  ScrollOneLineDown(Widget w, XEvent *event, String *p, Cardinal *n)
  {
      Scroll((TextWidget)w, event, XawsdRight);
  }
  
  static void
  MovePage(TextWidget ctx, XEvent *event, XawTextScanDirection dir)
  {
      int scroll_val = 0;
      XawTextPosition old_pos;
  
      ctx->text.from_left = -1;
      switch (dir) {
  	case XawsdLeft:
  	    if (ctx->text.lt.top != 0)
  		scroll_val = -Max(1, ctx->text.lt.lines - 1);
  		break;
  	case XawsdRight:
  	    if (!IsPositionVisible(ctx, Max(0, ctx->text.lastPos)))
  		scroll_val = Max(1, ctx->text.lt.lines - 1);
  	    break;
      }
  
      if (scroll_val)
  	XawTextScroll(ctx, scroll_val,
  		      ctx->text.left_margin - ctx->text.r_margin.left);
  
      old_pos = ctx->text.insertPos;
      switch (dir) {
  	case XawsdRight:
  	    if (IsPositionVisible(ctx, Max(0, ctx->text.lastPos)))
  		ctx->text.insertPos = Max(0, ctx->text.lastPos);
  	    else
  		ctx->text.insertPos = ctx->text.lt.top;
  	    if (ctx->text.insertPos < old_pos)
  		ctx->text.insertPos = SrcScan(ctx->text.source, old_pos,
  					      XawstEOL, XawsdLeft, 1, False);
  	    break;
  	case XawsdLeft:
  	    if (IsPositionVisible(ctx, 0))
  		ctx->text.insertPos = 0;
  	    else if (ctx->text.lt.lines)
  		ctx->text.insertPos =
  		    ctx->text.lt.info[ctx->text.lt.lines - 1].position;
  	    else
  		ctx->text.insertPos = ctx->text.lt.top;
  	    if (ctx->text.insertPos > old_pos)
  		ctx->text.insertPos = SrcScan(ctx->text.source, old_pos,
  					      XawstEOL, XawsdLeft, 1, False);
  	    break;
      }
  }
  
  static void
  MoveNextPage(Widget w, XEvent *event, String *p, Cardinal *n)
  {
      TextWidget ctx = (TextWidget)w;
      short mult = MULT(ctx);
  
      if (mult < 0) {
  	ctx->text.mult = -mult;
  	MovePreviousPage(w, event, p, n);
  	return;
      }
  
      if (ctx->text.insertPos < ctx->text.lastPos) {
  	XawTextUnsetSelection(w);
  	StartAction(ctx, event);
  	ctx->text.clear_to_eol = True;
  	while (mult-- && ctx->text.insertPos < ctx->text.lastPos)
  	    MovePage(ctx, event, XawsdRight);
  	EndAction(ctx);
      }
      else
  	ctx->text.mult = 1;
  }
  
  /*ARGSUSED*/
  static void
  MovePreviousPage(Widget w, XEvent *event, String *p, Cardinal *n)
  {
      TextWidget ctx = (TextWidget)w;
      short mult = MULT(ctx);
  
      if (mult < 0) {
  	ctx->text.mult = -mult;
  	MoveNextPage(w, event, p, n);
  	return;
      }
  
      if (ctx->text.insertPos > 0) {
  	XawTextUnsetSelection(w);
  	StartAction(ctx, event);
  	ctx->text.clear_to_eol = True;
  	while (mult-- && ctx->text.insertPos > 0)
  	    MovePage(ctx, event, XawsdLeft);
  	EndAction(ctx);
      }
      else
  	ctx->text.mult = 1;
  }
  
  /*
   * Delete Routines
   */
  static Bool
  MatchSelection(Atom selection, XawTextSelection *s)
  {
      Atom *match;
      int count;
  
      for (count = 0, match = s->selections; count < s->atom_count;
  	 match++, count++)
  	if (*match == selection)
  	    return (True);
  
      return (False);
  }
  
  #define SrcCvtSel	XawTextSourceConvertSelection
  
  static Boolean
  ConvertSelection(Widget w, Atom *selection, Atom *target, Atom *type,
  		 XtPointer *value, unsigned long *length, int *format)
  {
      Display *d = XtDisplay(w);
      TextWidget ctx = (TextWidget)w;
      Widget src = ctx->text.source;
      XawTextEditType edit_mode;
      Arg args[1];
      XawTextSelectionSalt *salt = NULL;
      XawTextSelection *s;
  
      if (*target == XA_TARGETS(d)) {
  	Atom *targetP, *std_targets;
  	unsigned long std_length;
  
  	if (SrcCvtSel(src, selection, target, type, value, length, format))
  	    return (True);
  
  	XtSetArg(args[0], XtNeditType,&edit_mode);
  	XtGetValues(src, args, 1);
  
  	XmuConvertStandardSelection(w, ctx->text.time, selection,
  				    target, type, (XPointer *)&std_targets,
  				    &std_length, format);
  
  	*length = 7 + (edit_mode == XawtextEdit) + std_length;
  	*value = XtMalloc((unsigned)sizeof(Atom)*(*length));
  	targetP = *(Atom**)value;
  	*targetP++ = XA_STRING;
  	*targetP++ = XA_TEXT(d);
  	*targetP++ = XA_UTF8_STRING(d);
  	*targetP++ = XA_COMPOUND_TEXT(d);
  	*targetP++ = XA_LENGTH(d);
  	*targetP++ = XA_LIST_LENGTH(d);
  	*targetP++ = XA_CHARACTER_POSITION(d);
  	if (edit_mode == XawtextEdit) {
  	    *targetP++ = XA_DELETE(d);
  	}
  	memcpy((char*)targetP, (char*)std_targets, sizeof(Atom)*std_length);
  	XtFree((char*)std_targets);
  	*type = XA_ATOM;
  	*format = 32;
  	return (True);
      }
  
      if (SrcCvtSel(src, selection, target, type, value, length, format))
  	return (True);
  
      for (salt = ctx->text.salt2; salt; salt = salt->next)
  	if (MatchSelection (*selection, &salt->s))
  	    break;
      if (!salt)
  	return (False);
      s = &salt->s;
      if (*target == XA_STRING
  	|| *target == XA_TEXT(d)
  	|| *target == XA_UTF8_STRING(d)
  	|| *target == XA_COMPOUND_TEXT(d)) {
  	if (*target == XA_TEXT(d)) {
  	    if (XawTextFormat(ctx, XawFmtWide))
  		*type = XA_COMPOUND_TEXT(d);
  	    else
  		*type = XA_STRING;
  	}
  	else
  	  *type = *target;
  
  	/*
  	 * If salt is True, the salt->contents stores CT string,
  	 * its length is measured in bytes.
  	 * Refer to _XawTextSaltAwaySelection()
  	 *
  	 * by Li Yuhong, Mar. 20, 1991.
  	 */
  	if (!salt) {
  	    *value = (char *)_XawTextGetSTRING(ctx, s->left, s->right);
  	    if (XawTextFormat(ctx, XawFmtWide)) {
  		XTextProperty textprop;
  		if (XwcTextListToTextProperty(d, (wchar_t**)value, 1,
  					      XCompoundTextStyle, &textprop)
  		    < Success) {
  		    XtFree(*value);
  		    return (False);
  		}
  		XtFree(*value);
  		*value = (XtPointer)textprop.value;
  		*length = textprop.nitems;
  	    }
  	    else
  		*length = strlen(*value);
  	}
  	else {
  	    *value = XtMalloc((salt->length + 1) * sizeof(unsigned char));
  	    strcpy (*value, salt->contents);
  	    *length = salt->length;
  	}
  	/* Got *value,*length, now in COMPOUND_TEXT format. */
  	if (XawTextFormat(ctx, XawFmtWide)) {
  	    if (*type == XA_STRING) {
  		XTextProperty textprop;
  		wchar_t **wlist;
  		int count;
  
  		textprop.encoding = XA_COMPOUND_TEXT(d);
  		textprop.value = (unsigned char *)*value;
  		textprop.nitems = strlen(*value);
  		textprop.format = 8;
  		if (XwcTextPropertyToTextList(d, &textprop, &wlist, &count)
  		     < Success
  		    || count < 1) {
  		    XtFree(*value);
  		    return (False);
  		}
  		XtFree(*value);
  		if (XwcTextListToTextProperty(d, wlist, 1, XStringStyle, &textprop)
  		     < Success) {
  		    XwcFreeStringList((wchar_t**)wlist);
  		    return (False);
  		}
  		*value = (XtPointer)textprop.value;
  		*length = textprop.nitems;
  		XwcFreeStringList((wchar_t**) wlist);
  	    }
  	    else if (*type == XA_UTF8_STRING(d)) {
  		XTextProperty textprop;
  		char **list;
  		int count;
  
  		textprop.encoding = XA_COMPOUND_TEXT(d);
  		textprop.value = (unsigned char *)*value;
  		textprop.nitems = strlen(*value);
  		textprop.format = 8;
  		if (Xutf8TextPropertyToTextList(d, &textprop, &list, &count)
  		    < Success
  		    || count < 1) {
  		    XtFree(*value);
  		    return (False);
  		}
  		XtFree(*value);
  		*value = *list;
  		*length = strlen(*list);
  		XFree(list);
  	    }
  	}
  	*format = 8;
  	return (True);
      }
  
      if (*target == XA_LIST_LENGTH(d) || *target == XA_LENGTH(d)) {
  	long *temp;
  
  	temp = (long *)XtMalloc(sizeof(long));
  	if (*target == XA_LIST_LENGTH(d))
  	    *temp = 1L;
  	else			/* *target == XA_LENGTH(d) */
  	    *temp = (long)(s->right - s->left);
  
  	*value = (XPointer)temp;
  	*type = XA_INTEGER;
  	*length = 1L;
  	*format = 32;
  	return (True);
      }
  
      if (*target == XA_CHARACTER_POSITION(d)) {
  	long *temp;
  
  	temp = (long *) XtMalloc(2 * sizeof(long));
  	temp[0] = (long)(s->left + 1);
  	temp[1] = s->right;
  	*value = (XPointer)temp;
  	*type = XA_SPAN(d);
  	*length = 2L;
  	*format = 32;
  	return (True);
      }
  
      if (*target == XA_DELETE(d)) {
  	if (!salt)
  	    _XawTextZapSelection(ctx, NULL, True);
  	*value = NULL;
  	*type = XA_NULL(d);
  	*length = 0;
  	*format = 32;
  	return (True);
      }
  
      if (XmuConvertStandardSelection(w, ctx->text.time, selection, target, type,
  				    (XPointer *)value, length, format))
  	return (True);
    
      return (False);
  }
  
  static void
  LoseSelection(Widget w, Atom *selection)
  {
      _LoseSelection(w, selection, NULL, NULL);
  }
  
  static void
  _LoseSelection(Widget w, Atom *selection, char **contents, int *length)
  {
      TextWidget ctx = (TextWidget)w;
      Atom *atomP;
      int i;
      XawTextSelectionSalt *salt, *prevSalt, *nextSalt;
  
      prevSalt = 0;
      for (salt = ctx->text.salt2; salt; salt = nextSalt) {
  	atomP = salt->s.selections;
  	nextSalt = salt->next;
  	for (i = 0 ; i < salt->s.atom_count; i++, atomP++)
  	    if (*selection == *atomP)
  		*atomP = (Atom)0;
  
  	while (salt->s.atom_count
  	       && salt->s.selections[salt->s.atom_count-1] == 0)
  	    salt->s.atom_count--;
  
  	/*
  	 * Must walk the selection list in opposite order from UnsetSelection.
  	 */
  	atomP = salt->s.selections;
  	for (i = 0 ; i < salt->s.atom_count; i++, atomP++)
  	    if (*atomP == (Atom)0) {
  		*atomP = salt->s.selections[--salt->s.atom_count];
  
  		while (salt->s.atom_count
  		       && salt->s.selections[salt->s.atom_count-1] == 0)
  		    salt->s.atom_count--;
  	    }
  	if (salt->s.atom_count == 0) {
  #ifndef OLDXAW
  	    if (contents == NULL) {
  		XawTextKillRing *kill_ring = XtNew(XawTextKillRing);
  
  		kill_ring->next = xaw_text_kill_ring;
  		kill_ring->contents = salt->contents;
  		kill_ring->length = salt->length;
  		kill_ring->format = XawFmt8Bit;
  		xaw_text_kill_ring = kill_ring;
  		kill_ring_prev.next = xaw_text_kill_ring;
  
  		if (++num_kill_rings > MAX_KILL_RINGS) {
  		    XawTextKillRing *tail = NULL;
  
  		    while (kill_ring->next) {
  			tail = kill_ring;
  			kill_ring = kill_ring->next;
  		    }
  		    if (kill_ring->refcount == 0) {
  			--num_kill_rings;
  			tail->next = NULL;
  			XtFree(kill_ring->contents);
  			XtFree((char*)kill_ring);
  		    }
  		}
  	    }
  	    else {
  		*contents = salt->contents;
  		*length = salt->length;
  	    }
  #endif
  	    if (prevSalt)
  		prevSalt->next = nextSalt;
  	    else
  		ctx->text.salt2 = nextSalt;
  
  	    XtFree((char *)salt->s.selections);
  	    XtFree((char *)salt);
  	}
  	else
  	    prevSalt = salt;
      }
  }
  
  static void
  _DeleteOrKill(TextWidget ctx, XawTextPosition from, XawTextPosition to,
  	      Bool kill)
  {
      XawTextBlock text;
  
  #ifndef OLDXAW
      if (ctx->text.kill_ring_ptr) {
  	--ctx->text.kill_ring_ptr->refcount;
  	ctx->text.kill_ring_ptr = NULL;
      }
  #endif
      if (kill && from < to) {
  #ifndef OLDXAW
  	Bool append = False;
  	char *ring = NULL;
  	XawTextPosition old_from = from;
  #endif
  	char *string;
  	int size = 0, length;
  	XawTextSelectionSalt *salt;
  	Atom selection = XInternAtom(XtDisplay(ctx), "SECONDARY", False);
  
  #ifndef OLDXAW
  	if (ctx->text.kill_ring == KILL_RING_APPEND) {
  	    old_from = ctx->text.salt2->s.left;
  	    append = True;
  	}
  	else
  	    ctx->text.kill_ring = KILL_RING_BEGIN;
  
  	if (append)
  	    _LoseSelection((Widget)ctx, &selection, &ring, &size);
  	else
  #endif
  	    LoseSelection((Widget)ctx, &selection);
  
  	salt = (XawTextSelectionSalt*)XtMalloc(sizeof(XawTextSelectionSalt));
  	salt->s.selections = (Atom *)XtMalloc(sizeof(Atom));
  	salt->s.left = from;
  	salt->s.right = to;
  
  	string = (char *)_XawTextGetSTRING(ctx, from, to);
  
  	if (XawTextFormat(ctx, XawFmtWide)) {
  	    XTextProperty textprop;
  
  	    if (XwcTextListToTextProperty(XtDisplay((Widget)ctx),
  					  (wchar_t**)(&string),
  					  1, XCompoundTextStyle,
  					  &textprop) <  Success) {
  		XtFree(string);
  		XtFree((char*)salt->s.selections);
  		XtFree((char*)salt);
  		return;
  	    }
  	    XtFree(string);
  	    string = (char *)textprop.value;
  	    length = textprop.nitems;
  	}
  	else
  	    length = strlen(string);
  
  	salt->length = length + size;
  
  #ifndef OLDXAW
  	if (!append)
  	    salt->contents = string;
  	else {
  	    salt->contents = XtMalloc(length + size + 1);
  	    if (from >= old_from) {
  		strncpy(salt->contents, ring, size);
  		salt->contents[size] = '\0';
  		strncat(salt->contents, string, length);
  	    }
  	    else {
  		strncpy(salt->contents, string, length);
  		salt->contents[length] = '\0';
  		strncat(salt->contents, ring, size);
  	    }
  	    salt->contents[length + size] = '\0';
  	    XtFree(ring);
  	    XtFree(string);
  	}
  
  	kill_ring_prev.contents = salt->contents;
  	kill_ring_prev.length = salt->length;
  	kill_ring_prev.format = XawFmt8Bit;
  #else
  	salt->contents = string;
  #endif
  
  	salt->next = ctx->text.salt2;
  	ctx->text.salt2 = salt;
  
  #ifndef OLDXAW
  	if (append)
  	    ctx->text.kill_ring = KILL_RING_BEGIN;
  #endif
  
  	salt->s.selections[0] = selection;
  
  	XtOwnSelection((Widget)ctx, selection, ctx->text.time,
  		       ConvertSelection, LoseSelection, NULL);
  	salt->s.atom_count = 1;
      }
      text.length = 0;
      text.firstPos = 0;
  
      text.format = _XawTextFormat(ctx);
      text.ptr = "";
  
      if (_XawTextReplace(ctx, from, to, &text)) {
  	XBell(XtDisplay(ctx), 50);
  	return;
      }
      ctx->text.from_left = -1;
      ctx->text.insertPos = from;
      ctx->text.showposition = TRUE;
  }
  
  static void
  DeleteOrKill(TextWidget ctx, XEvent *event, XawTextScanDirection dir,
  	     XawTextScanType type, Bool include, Bool kill)
  {
      XawTextPosition from, to;
      short mult = MULT(ctx);
  
      if (mult < 0) {
  	mult = -mult;
  	dir = dir == XawsdLeft ? XawsdRight : XawsdLeft;
      }
  
      StartAction(ctx, event);
  #ifndef OLDXAW
      if (mult == 1)
  	_XawSourceSetUndoMerge((TextSrcObject)ctx->text.source, True);
  #endif
      to = SrcScan(ctx->text.source, ctx->text.insertPos,
  		 type, dir, mult, include);
  
      /*
       * If no movement actually happened, then bump the count and try again.
       * This causes the character position at the very beginning and end of
       * a boundary to act correctly
       */
      if (to == ctx->text.insertPos)
  	to = SrcScan(ctx->text.source, ctx->text.insertPos,
  		     type, dir, mult + 1, include);
  
      if (dir == XawsdLeft) {
  	from = to;
  	to = ctx->text.insertPos;
      }
      else 
  	from = ctx->text.insertPos;
  
      _DeleteOrKill(ctx, from, to, kill);
      EndAction(ctx);
  }
  
  static void
  Delete(Widget w, XEvent *event, String *p, Cardinal *n)
  {
      TextWidget ctx = (TextWidget)w;
  
      if (ctx->text.s.left != ctx->text.s.right)
  	DeleteCurrentSelection(w, event, p, n);
      else
  	DeleteBackwardChar(w, event, p, n);
  }
  
  static void
  DeleteChar(Widget w, XEvent *event, XawTextScanDirection dir)
  {
      TextWidget ctx = (TextWidget)w;
      short mul = MULT(ctx);
  
      if (mul < 0) {
  	ctx->text.mult = mul = -mul;
  	dir = dir == XawsdLeft ? XawsdRight : XawsdLeft;
      }
      DeleteOrKill(ctx, event, dir, XawstPositions, True, False);
  #ifndef OLDXAW
      if (mul == 1)
  	_XawSourceSetUndoErase((TextSrcObject)ctx->text.source,
  			       dir == XawsdLeft ? -1 : 1);
  #endif
  }
  
  /*ARGSUSED*/
  static void
  DeleteForwardChar(Widget w, XEvent *event, String *p, Cardinal *n)
  {
      DeleteChar(w, event, XawsdRight);
  }
  
  /*ARGSUSED*/
  static void
  DeleteBackwardChar(Widget w, XEvent *event, String *p, Cardinal *n)
  {
      DeleteChar(w, event, XawsdLeft);
  }
  
  static void
  DeleteForwardWord(Widget w, XEvent *event, String *params, Cardinal *num_params)
  {
      XawTextScanType type;
  
      if (*num_params && (*params[0] == 'A' || *params[0] == 'a'))
  	type = XawstAlphaNumeric;
      else
  	type = XawstWhiteSpace;
  
      DeleteOrKill((TextWidget)w, event, XawsdRight, type, False, False);
  }
  
  static void
  DeleteBackwardWord(Widget w, XEvent *event, String *params, Cardinal *num_params)
  {
      XawTextScanType type;
  
      if (*num_params && (*params[0] == 'A' || *params[0] == 'a'))
  	type = XawstAlphaNumeric;
      else
  	type = XawstWhiteSpace;
  
      DeleteOrKill((TextWidget)w, event, XawsdLeft, type, False, False);
  }
  
  static void
  KillForwardWord(Widget w, XEvent *event, String *params, Cardinal *num_params)
  {
      XawTextScanType type;
  
      if (*num_params && (*params[0] == 'A' || *params[0] == 'a'))
  	type = XawstAlphaNumeric;
      else
  	type = XawstWhiteSpace;
  
      DeleteOrKill((TextWidget)w, event, XawsdRight, type, False, True);
  }
  
  static void
  KillBackwardWord(Widget w, XEvent *event, String *params, Cardinal *num_params)
  {
      XawTextScanType type;
  
      if (*num_params && (*params[0] == 'A' || *params[0] == 'a'))
  	type = XawstAlphaNumeric;
      else
  	type = XawstWhiteSpace;
  
      DeleteOrKill((TextWidget) w, event, XawsdLeft, type, False, True);
  }
  
  /*ARGSUSED*/
  static void
  KillToEndOfLine(Widget w, XEvent *event, String *p, Cardinal *n)
  {
      TextWidget ctx = (TextWidget)w;
      XawTextPosition end_of_line;
      XawTextScanDirection dir = XawsdRight;
      short mult = MULT(ctx);
  
      if (mult < 0) {
  	dir = XawsdLeft;
  	mult = -mult;
      }
  
      StartAction(ctx, event);
      end_of_line = SrcScan(ctx->text.source, ctx->text.insertPos, XawstEOL,
  			  dir, mult, False);
      if (end_of_line == ctx->text.insertPos)
  	end_of_line = SrcScan(ctx->text.source, ctx->text.insertPos, XawstEOL,
  			      dir, mult, True);
  
      if (dir == XawsdRight)
  	_DeleteOrKill(ctx, ctx->text.insertPos, end_of_line, True);
      else
  	_DeleteOrKill(ctx, end_of_line, ctx->text.insertPos, True);
      EndAction(ctx);
  }
  
  /*ARGSUSED*/
  static void
  KillToEndOfParagraph(Widget w, XEvent *event, String *p, Cardinal *n)
  {
      DeleteOrKill((TextWidget)w, event, XawsdRight, XawstParagraph, False, True);
  }
  
  void
  _XawTextZapSelection(TextWidget ctx, XEvent *event, Bool kill)
  {
      StartAction(ctx, event);
      _DeleteOrKill(ctx, ctx->text.s.left, ctx->text.s.right, kill);
      EndAction(ctx);
  }
  
  /*ARGSUSED*/
  static void
  KillCurrentSelection(Widget w, XEvent *event, String *p, Cardinal *n)
  {
      _XawTextZapSelection((TextWidget) w, event, True);
  }
  
  #ifndef OLDXAW
  /*ARGSUSED*/
  static void
  KillRingYank(Widget w, XEvent *event, String *params, Cardinal *num_params)
  {
      TextWidget ctx = (TextWidget)w;
      XawTextPosition insertPos = ctx->text.insertPos;
      Bool first_yank = False;
  
      if (ctx->text.s.left != ctx->text.s.right)
  	XawTextUnsetSelection((Widget)ctx);
  
      StartAction(ctx, event);
  
      if (ctx->text.kill_ring_ptr == NULL) {
  	ctx->text.kill_ring_ptr = &kill_ring_prev;
  	++ctx->text.kill_ring_ptr->refcount;
  	ctx->text.s.left = ctx->text.s.right = insertPos;
  	first_yank = True;
      }
      if (ctx->text.kill_ring_ptr) {
  	int mul = MULT(ctx);
  	XawTextBlock text;
  
  	if (!first_yank) {
  	    if (mul < 0)
  		mul = 1;
  	    --ctx->text.kill_ring_ptr->refcount;
  	    while (mul--) {
  		if ((ctx->text.kill_ring_ptr = ctx->text.kill_ring_ptr->next) == NULL)
  		    ctx->text.kill_ring_ptr = &kill_ring_null;
  	    }
  	    ++ctx->text.kill_ring_ptr->refcount;
  	}
  	text.firstPos = 0;
  	text.length = ctx->text.kill_ring_ptr->length;
  	text.ptr = ctx->text.kill_ring_ptr->contents;
  	text.format = ctx->text.kill_ring_ptr->format;
  
  	if (_XawTextReplace(ctx, ctx->text.s.left, insertPos, &text) == XawEditDone) {
  	    ctx->text.kill_ring = KILL_RING_YANK;
  	    ctx->text.insertPos = ctx->text.s.left + text.length;
  	}
      }
      else
  	XBell(XtDisplay(w), 0);
  
      EndAction(ctx);
  }
  #endif /* OLDXAW */
  
  /*ARGSUSED*/
  static void
  DeleteCurrentSelection(Widget w, XEvent *event, String *p, Cardinal *n)
  {
      _XawTextZapSelection((TextWidget)w, event, False);
  }
  
  #ifndef OLDXAW
  #define CHECK_SAVE()						\
  	if (save && !save->ptr)					\
  	    save->ptr = _XawTextGetText(ctx, save->firstPos,	\
  		save->firstPos + save->length)
  static Bool
  StripSpaces(TextWidget ctx, XawTextPosition left, XawTextPosition right,
  	    XawTextPosition *pos, int num_pos, XawTextBlock *save)
  {
      Bool done, space;
      int i, cpos, count = 0;
      XawTextBlock block, text;
      XawTextPosition ipos, position = left, tmp = left;
  
      text.firstPos = 0;
      text.format = XawFmt8Bit;
      text.ptr = " ";
      text.length = 1;
  
      position = XawTextSourceRead(ctx->text.source, position,
  				 &block, right - left);
      done = False;
      space = False;
      /* convert tabs and returns to spaces */
      while (!done) {
  	if (XawTextFormat(ctx, XawFmt8Bit)) {
  	    for (i = 0; i < block.length; i++)
  		if (block.ptr[i] == '\t' || block.ptr[i] == '\n') {
  		    space = True;
  		    break;
  		}
  	}
  	else {
  	    wchar_t *wptr = (wchar_t*)block.ptr;
  	    for (i = 0; i < block.length; i++)
  		if (wptr[i] == _Xaw_atowc('\t') || wptr[i] == _Xaw_atowc('\n')) {
  		    space = True;
  		    break;
  		}
  	}
  	if (space) {
  	    CHECK_SAVE();
  	    if (_XawTextReplace(ctx, tmp + i, tmp + i + 1, &text))
  		return (False);
  	    space = False;
  	}
  	tmp += i;
  	position = XawTextSourceRead(ctx->text.source, tmp,
  				     &block, right - tmp);
  	if (block.length == 0 || tmp == position || tmp >= right)
  	    done = True;
      }
  
      text.ptr = "";
      text.length = 0;
      position = tmp = left;
      position = XawTextSourceRead(ctx->text.source, position,
  				 &block, right - left);
      ipos = ctx->text.insertPos;
      done = False;
      while (!done) {
  	if (XawTextFormat(ctx, XawFmt8Bit)) {
  	    for (i = 0; i < block.length; i++)
  		if (block.ptr[i] == ' ')
  		    ++count;
  		else if (count == 1)
  		    count = 0;
  		else if (count)
  		    break;
  	}
  	else {
  	    wchar_t *wptr = (wchar_t*)block.ptr;
  	    for (i = 0; i < block.length; i++)
  		if (wptr[i] == _Xaw_atowc(' '))
  		    ++count;
  		else if (count == 1)
  		    count = 0;
  		else if (count)
  		    break;
  	}
  	if (--count > 0) {
  	    CHECK_SAVE();
  	    if (_XawTextReplace(ctx, tmp + i - count, tmp + i, &text))
  		return (False);
  	    right -= count;
  	    if (num_pos) {
  		for (cpos = 0; cpos < num_pos; cpos++) {
  		    if (tmp + i - count < pos[cpos]) {
  			if (tmp + i < pos[cpos])
  			    pos[cpos] -= count;
  			else
  			    pos[cpos] = tmp + i - count;
  		    }
  		}
  	    }
  	    else {
  		if (tmp + i - count < ipos) {
  		    if (tmp + i < ipos)
  			ipos -= count;
  		    else
  			ipos = tmp + i - count;
  		}
  	    }
  	    tmp += i - count;
  	}
  	else
  	    tmp += i + 1;
  	count = 0;
  	position = XawTextSourceRead(ctx->text.source, tmp,
  				     &block, right - tmp);
  	if (block.length == 0 || tmp == position || tmp >= right)
  	    done = True;
      }
      if (!num_pos)
  	ctx->text.insertPos = ipos;
  
      return (True);
  }
  
  static Bool
  Tabify(TextWidget ctx, XawTextPosition left, XawTextPosition right,
         XawTextPosition *pos, int num_pos, XawTextBlock *save)
  {
      Bool done, zero;
      int i, cpos, count = 0, column = 0, offset = 0;
      XawTextBlock text, block;
      XawTextPosition ipos, position = left, tmp = left;
      TextSinkObject sink = (TextSinkObject)ctx->text.sink;
      short *char_tabs = sink->text_sink.char_tabs;
      int tab_count = sink->text_sink.tab_count;
      int tab_index = 0, tab_column = 0, TAB_SIZE = DEFAULT_TAB_SIZE;
  
      text.firstPos = 0;
      text.ptr = "\t";
      text.format = XawFmt8Bit;
      text.length = 1;
  
      position = XawTextSourceRead(ctx->text.source, position,
  				 &block, right - left);
      ipos = ctx->text.insertPos;
      done = zero = False;
      if (tab_count)
  	TAB_SIZE = *char_tabs;
      while (!done) {
  	if (XawTextFormat(ctx, XawFmt8Bit)) {
  	    for (i = 0; i < block.length; i++) {
  		++offset;
  		++column;
  		if (tab_count) {
  		    if (column > tab_column + char_tabs[tab_index]) {
  			TAB_SIZE = tab_index < tab_count - 1 ? char_tabs[tab_index + 1] - char_tabs[tab_index] : *char_tabs;
  			if (++tab_index >= tab_count) {
  			    tab_column += char_tabs[tab_count - 1];
  			    tab_index = 0;
  			}
  		    }
  		}
  		if (block.ptr[i] == ' ') {
  		    if (++count > TAB_SIZE)
  			count %= TAB_SIZE;
  		    if ((tab_count && column == tab_column + char_tabs[tab_index]) ||
  			(!tab_count && column % TAB_SIZE == 0)) {
  			if (count % (TAB_SIZE + 1) > 1)
  			    break;
  			else
  			    count = 0;
  		    }
  		}
  		else {
  		    if (block.ptr[i] == '\n') {
  			zero = True;
  			break;
  		    }
  		    count = 0;
  		}
  	    }
  	}
  	else {
  	    wchar_t *wptr = (wchar_t*)block.ptr;
  	    for (i = 0; i < block.length; i++) {
  		++offset;
  		++column;
  		if (tab_count) {
  		    if (column > tab_column + char_tabs[tab_index]) {
  			TAB_SIZE = tab_index < tab_count - 1 ? char_tabs[tab_index + 1] - char_tabs[tab_index] : *char_tabs;
  			if (++tab_index >= tab_count) {
  			    tab_column += char_tabs[tab_count - 1];
  			    tab_index = 0;
  			}
  		    }
  		}
  		if (wptr[i] == _Xaw_atowc(' ')) {
  		    if (++count > TAB_SIZE)
  			count %= TAB_SIZE;
  		    if ((tab_count && column == tab_column + char_tabs[tab_index]) ||
  			(!tab_count && column % TAB_SIZE == 0)) {
  			if (count % (TAB_SIZE + 1) > 1)
  			    break;
  			else
  			    count = 0;
  		    }
  		}
  		else {
  		    if (wptr[i] == _Xaw_atowc('\n')) {
  			zero = True;
  			break;
  		    }
  		    count = 0;
  		}
  	    }
  	}
  	count %= TAB_SIZE + 1;
  	if (!zero && count > 1 && i < block.length) {
  	    CHECK_SAVE();
  	    if (_XawTextReplace(ctx, tmp + i - count + 1, tmp + i + 1, &text))
  		return (False);
  	    right -= count - 1;
  	    offset -= count - 1;
  	    if (num_pos) {
  		for (cpos = 0; cpos < num_pos; cpos++) {
  		    if (tmp + i - count + 1 < pos[cpos]) {
  			if (tmp + i + 1 < pos[cpos])
  			    pos[cpos] -= count;
  			else
  			    pos[cpos] = tmp + i - count + 1;
  			++pos[cpos];
  		    }
  		}
  	    }
  	    else {
  		if (tmp + i - count + 1 < ipos) {
  		    if (tmp + i + 1 < ipos)
  			ipos -= count;
  		    else
  			ipos = tmp + i - count + 1;
  		    ++ipos;
  		}
  	    }
  	}
  	if (count)
  	    --count;
  	if (zero) {
  	    count = column = 0;
  	    zero = False;
  	    if (tab_count) {
  		tab_column = tab_index = 0;
  		TAB_SIZE = *char_tabs;
  	    }
  	}
  	else if (i < block.length)
  	    count = 0;
  	tmp = left + offset;
  	position = XawTextSourceRead(ctx->text.source, tmp,
  				     &block, right - tmp);
  	if (tmp == position || tmp >= right)
  	    done = True;
      }
      if (!num_pos)
  	ctx->text.insertPos = ipos;
  
      return (True);
  }
  
  static Bool
  Untabify(TextWidget ctx, XawTextPosition left, XawTextPosition right,
  	 XawTextPosition *pos, int num_pos, XawTextBlock *save)
  {
      Bool done, zero;
      int i, cpos, count = 0, diff = 0;
      XawTextBlock block, text;
      XawTextPosition ipos, position = left, tmp = left;
      TextSinkObject sink = (TextSinkObject)ctx->text.sink;
      short *char_tabs = sink->text_sink.char_tabs;
      int tab_count = sink->text_sink.tab_count;
      int tab_index = 0, tab_column = 0, tab_base = 0;
      static char *tabs = "        ";
  
      text.firstPos = 0;
      text.format = XawFmt8Bit;
      text.ptr = tabs;
  
      position = XawTextSourceRead(ctx->text.source, position,
  				 &block, right - left);
      ipos = ctx->text.insertPos;
      done = False;
      zero = False;
      while (!done) {
  	if (XawTextFormat(ctx, XawFmt8Bit))
  	    for (i = 0; i < block.length; i++) {
  		if (block.ptr[i] != '\t') {
  		    ++count;
  		    if (block.ptr[i] == '\n') {
  			zero = True;
  			break;
  		    }
  		}
  		else
  		    break;
  	}
  	else {
  	    wchar_t *wptr = (wchar_t*)block.ptr;
  	    for (i = 0; i < block.length; i++)
  		if (wptr[i] != _Xaw_atowc('\t')) {
  		    ++count;
  		    if (wptr[i] != _Xaw_atowc('\n')) {
  			zero = True;
  			break;
  		    }
  		}
  		else
  		    break;
  	}
  	if (!zero && i < block.length) {
  	    if (tab_count) {
  		while (tab_base + tab_column <= count) {
  		    for (; tab_index < tab_count; ++tab_index)
  			if (tab_base + char_tabs[tab_index] > count) {
  			    tab_column = char_tabs[tab_index];
  			    break;
  			}
  		    if (tab_index >= tab_count) {
  			tab_base += char_tabs[tab_count - 1];
  			tab_column = tab_index = 0;
  		    }
  		}
  		text.length = (tab_base + tab_column) - count;
  		if (text.length > 8) {
  		    int j;
  
  		    text.ptr = XtMalloc(text.length);
  		    for (j = 0; j < text.length; j++)
  			text.ptr[j] = ' ';
  		}
  		else
  		    text.ptr = tabs;
  	    }
  	    else
  		text.length = DEFAULT_TAB_SIZE - (count % DEFAULT_TAB_SIZE);
  	    CHECK_SAVE();
  	    if (_XawTextReplace(ctx, tmp + i, tmp + i + 1, &text)) {
  		if (tab_count && text.length > 8)
  		    XtFree(text.ptr);
  		return (False);
  	    }
  	    if (tab_count && text.length > 8)
  		XtFree(text.ptr);
  	    count += text.length;
  	    right += text.length - 1;
  	    if (num_pos) {
  		for (cpos = 0; cpos < num_pos; cpos++) {
  		    if (tmp + i < pos[cpos]) {
  			if (tmp + i + 1 < pos[cpos])
  			    --pos[cpos];
  			else
  			    pos[cpos] = tmp + i;
  			pos[cpos] += text.length;
  		    }
  		}
  	    }
  	    else {
  		if (tmp + i < ipos) {
  		    if (tmp + i + 1 < ipos)
  			--ipos;
  		    else
  			ipos = tmp + i;
  		    ipos += text.length;
  		}
  	    }
  	}
  	tmp = left + count + diff;
  	if (zero) {
  	    diff += count;
  	    count = 0;
  	    zero = False;
  	    if (tab_count)
  		tab_base = tab_column = tab_index = 0;
  	}
  	position = XawTextSourceRead(ctx->text.source, tmp,
  				     &block, right - tmp);
  	if (tmp == position || tmp >= right)
  	    done = True;
      }
      if (!num_pos)
  	ctx->text.insertPos = ipos;
  
      return (True);
  }
  
  static int
  FormatText(TextWidget ctx, XawTextPosition left, Bool force,
  	   XawTextPosition *pos, int num_pos)
  {
      char *ptr = NULL;
      Bool freepos = False, undo, paragraph = pos != NULL;
      int i, result;
      XawTextBlock block, *text;
      XawTextPosition end = ctx->text.lastPos, buf[32];
      TextSrcObject src = (TextSrcObject)ctx->text.source;
      XawTextPosition right = SrcScan(ctx->text.source, left, XawstEOL,
  				    XawsdRight, 1, False);
  
      undo = src->textSrc.enable_undo && src->textSrc.undo_state == False;
      if (undo) {
  	if (!pos) {
  	    num_pos = src->textSrc.num_text;
  	    pos = XawStackAlloc(sizeof(XawTextPosition) * num_pos, buf);
  	    for (i = 0; i < num_pos; i++)
  		pos[i] = ((TextWidget)src->textSrc.text[i])->text.insertPos;
  	    freepos = True;
  	}
  	else
  	    freepos = False;
  	src->textSrc.undo_state = True;
  	block.ptr = NULL;
  	block.firstPos = left;
  	block.length = right - left;
  	text = &block;
      }
      else
  	text = NULL;
  
      result = DoFormatText(ctx, left, force, 1, text, pos, num_pos, paragraph);
      if (undo && result == XawEditDone && block.ptr) {
  	char *lbuf, *rbuf;
  	unsigned llen, rlen, size;
  
  	ptr = lbuf = block.ptr;
  	llen = block.length;
  	rlen = llen + (ctx->text.lastPos - end);
  
  	block.firstPos = 0;
  	block.format = _XawTextFormat(ctx);
  
  	rbuf = _XawTextGetText(ctx, left, left + rlen);
  
  	size = XawTextFormat(ctx, XawFmtWide) ? sizeof(wchar_t) : sizeof(char);
  	if (llen != rlen || memcmp(lbuf, rbuf, llen * size)) {
  	    block.ptr = lbuf;
  	    block.length = llen;
  	    _XawTextReplace(ctx, left, left + rlen, &block);
  
  	    src->textSrc.undo_state = False;
  	    block.ptr = rbuf;
  	    block.length = rlen;
  	    _XawTextReplace(ctx, left, left + llen, &block);
  	}
  	else
  	    src->textSrc.undo_state = False;
  	XtFree(rbuf);
      }
      if (undo) {
  	src->textSrc.undo_state = False;
  	if (freepos) {
  	    for (i = 0; i < num_pos; i++) {
  		TextWidget tw = (TextWidget)src->textSrc.text[i];
  		tw->text.insertPos = XawMin(XawMax(0, pos[i]), tw->text.lastPos);
  	    }
  	    XawStackFree(pos, buf);
  	}
  	if (ptr)
  	    XtFree(ptr);
      }
  
      return (result);
  }
  
  static int
  DoFormatText(TextWidget ctx, XawTextPosition left, Bool force, int level,
  	     XawTextBlock *save, XawTextPosition *pos, int num_pos,
  	     Bool paragraph)
  {
      XawTextPosition right = SrcScan(ctx->text.source, left, XawstEOL,
  				    XawsdRight, 1, False);
      XawTextPosition position, tmp, ipos;
      XawTextBlock block, text;
      char buf[128];
      wchar_t *wptr;
      int i, count, cpos;
      Bool done, force2 = force, recurse = False;
  
      position = XawTextSourceRead(ctx->text.source, left, &block, right - left);
      if (block.length == 0 || left >= right ||
  	(level == 1 && ((XawTextFormat(ctx, XawFmt8Bit) &&
  	 block.ptr[0] != ' ' &&
  	 block.ptr[0] != '\t' &&
  	 !isalnum(*(unsigned char*)block.ptr)) ||
  	(XawTextFormat(ctx, XawFmtWide) &&
  	 _Xaw_atowc(XawSP) != *(wchar_t*)block.ptr &&
  	 _Xaw_atowc(XawTAB) != *(wchar_t*)block.ptr &&
  	 !iswalnum(*(wchar_t*)block.ptr)))))
  	return (XawEditDone);
  
      if (level == 1 && !paragraph) {
  	tmp = ctx->text.lastPos;
  	if (Untabify(ctx, left, right, pos, num_pos, save) == False)
  	    return (XawEditError);
  	right += ctx->text.lastPos - tmp;
  	position = XawTextSourceRead(ctx->text.source, left, &block,
  				     right - left);
      }
  
      text.firstPos = 0;
      text.format = XawFmt8Bit;
  
      ipos = ctx->text.insertPos;
      count = 0;
      done = False;
      while (!done) {
  	if (XawTextFormat(ctx, XawFmt8Bit)) {
  	    for (i = 0; i < block.length; i++)
  		if (block.ptr[i] == ' ')
  		    ++count;
  		else {
  		    done = True;
  		    break;
  		}
  	}
  	else {
  	    wptr = (wchar_t*)block.ptr;
  	    for (i = 0; i < block.length; i++)
  		if (wptr[i] == _Xaw_atowc(' '))
  		    ++count;
  		else {
  		    done = True;
  		    break;
  		}
  	}
  	tmp = position;
  	position = XawTextSourceRead(ctx->text.source, position,
  				     &block, right - position);
  	if (tmp == position)
  	    done = True;
      }
      position = left + count;
      if (count < ctx->text.left_column) {
  	int bytes = ctx->text.left_column - count;
  
  	text.ptr = XawStackAlloc(bytes, buf);
  	text.length = bytes;
  	for (i = 0; i < bytes; i++)
  	    text.ptr[i] = ' ';
  	CHECK_SAVE();
  	if (_XawTextReplace(ctx, left, left, &text)) {
  	    XawStackFree(text.ptr, buf);
  	    return (XawEditError);
  	}
  	XawStackFree(text.ptr, buf);
  	right += bytes;
  	if (num_pos) {
  	    for (cpos = 0; cpos < num_pos; cpos++)
  		if (pos[cpos] >= left)
  		    pos[cpos] += bytes;
  	}
  	if (ipos >= left)
  	    ipos += bytes;
  	count += bytes;
      }
  
      done = False;
      if (!paragraph && level == 1
  	&& ipos <= right && ipos - left > ctx->text.right_column) {
  	XawTextPosition len = ctx->text.lastPos;
  	int skip = ctx->text.justify == XawjustifyRight
  		|| ctx->text.justify == XawjustifyCenter ?
  		ctx->text.left_column : count;
  
  	if (pos)
  	    for (i = 0; i < num_pos; i++)
  		if (pos[i] == ipos)
  		    break;
  
  	StripSpaces(ctx, left + skip, right, pos, num_pos, save);
  	right += ctx->text.lastPos - len;
  	if (pos && i < num_pos)
  	    ipos = pos[i];
  	else
  	    ipos = ctx->text.insertPos;
  	done = ipos - left > ctx->text.right_column;
  	count = skip + (count == skip + 1);
      }
      if ((paragraph || done) && right - left > ctx->text.right_column) {
  	position = tmp = right;
  	XawTextSourceRead(ctx->text.source, position - 1, &block, 1);
  	if (block.length &&
  	    ((XawTextFormat(ctx, XawFmt8Bit) &&
  	     block.ptr[0] == ' ') ||
  	    (XawTextFormat(ctx, XawFmtWide) &&
  	     _Xaw_atowc(XawSP) == *(wchar_t*)block.ptr)))
  	    --position;
  	while (position - left > ctx->text.right_column) {
  	    tmp = position;
  	    position = SrcScan(ctx->text.source, position,
  			       XawstWhiteSpace, XawsdLeft, 1, True);
  	}
  	if (position <= left + ctx->text.left_column)
  	    position = tmp;
  	if (position > left && position - left > ctx->text.left_column
  	    && position != right) {
  	    text.ptr = "\n";
  	    text.length = 1;
  	    CHECK_SAVE();
  	    if (_XawTextReplace(ctx, position, position + 1, &text))
  		return (XawEditError);
  	    right = position;
  	    recurse = True;
  	    force = True;
  	}
      }
  
      if (force) {
  	if (ctx->text.justify == XawjustifyCenter)
  	    count = ctx->text.right_column - (count - ctx->text.left_column);
  	else
  	    count = ctx->text.right_column;
  	if (count > right - left)
  	    count -= right - left;
  	else
  	    count = 0;
      }
      else
  	count = 0;
      if (count > 0) {
  	switch (ctx->text.justify) {
  	    case XawjustifyLeft:
  		break;
  	    case XawjustifyRight:
  	    case XawjustifyCenter:
  		if (ctx->text.justify == XawjustifyCenter) {
  		    int alnum = 0;
  
  		    if (!(count & 1)) {
  			XawTextSourceRead(ctx->text.source, right, &block, 1);
  			if ((XawTextFormat(ctx, XawFmt8Bit)
  			     && isalnum(*(unsigned char*)block.ptr)) ||
  			    (XawTextFormat(ctx, XawFmtWide)
  			     && iswalnum(*(wchar_t*)block.ptr)))
  			    alnum = 1;
  		    }
  		    count = (count + alnum) >> 1;
  		}
  		text.ptr = XawStackAlloc(count, buf);
  		text.length = count;
  		for (i = 0; i < count; i++)
  		    text.ptr[i] = ' ';
  		CHECK_SAVE();
  		if (_XawTextReplace(ctx, left, left, &text)) {
  		    XawStackFree(text.ptr, buf);
  		    return (XawEditError);
  		}
  		XawStackFree(text.ptr, buf);
  		position += count;
  		right += count;
  		if (num_pos) {
  		    for (cpos = 0; cpos < num_pos; cpos++)
  			if (pos[cpos] > left)
  			    pos[cpos] += count;
  		}
  		else if (ipos > left)
  		    ipos += count;
  		break;
  	    case XawjustifyFull:
  		i = 0;
  		tmp = left;
  		/*CONSTCOND*/
  		while (True) {
  		    tmp = SrcScan(ctx->text.source, tmp, XawstWhiteSpace,
  				  XawsdRight, 1, True);
  		    if (tmp < right)
  			++i;
  		    else
  			break;
  		}
  		if (i) {
  		    double inc, ii;
  		    int bytes, steps;
  
  		    bytes = count;
  		    inc = ii = (count + .5) / (double)i;
  
  		    steps = count;
  		    text.ptr = XawStackAlloc(steps, buf);
  		    for (i = 0; i < steps; i++)
  			text.ptr[i] = ' ';
  		    tmp = left;
  		    CHECK_SAVE();
  		    while (bytes) {
  			steps = 1;
  			while (inc + ii < 1) {
  			    ++steps;
  			    inc += ii;
  			}
  			tmp = SrcScan(ctx->text.source, tmp, XawstWhiteSpace,
  				      XawsdRight, steps, True);
  			if (bytes > inc)
  			    text.length = (int)inc;
  			else
  			    text.length = bytes;
  			bytes -= text.length;
  			if (_XawTextReplace(ctx, tmp, tmp, &text)) {
  			    XawStackFree(buf, text.ptr);
  			    return (XawEditError);
  			}
  			if (num_pos) {
  			    for (cpos = 0; cpos < num_pos; cpos++)
  				if (tmp <= pos[cpos])
  				    pos[cpos] += text.length;
  			}
  			else if (tmp <= ipos)
  			    ipos += text.length;
  			inc -= (int)inc;
  			inc += ii;
  		    }
  		    position += count;
  		    right += count;
  		    XawStackFree(buf, text.ptr);
  		}
  		break;
  	}
      }
  
      if (!num_pos)
  	ctx->text.insertPos = XawMin(ipos, ctx->text.lastPos);
  
      return (recurse ? DoFormatText(ctx, position + 1,
  				   ctx->text.justify != XawjustifyFull
  				   && (force2 || paragraph),
  				   ++level, save, pos, num_pos, paragraph)
  		 : XawEditDone);
  }
  #undef CHECK_SAVE
  
  /*ARGSUSED*/
  static void
  Indent(Widget w, XEvent *event, String *params, Cardinal *num_params)
  {
      TextWidget ctx = (TextWidget)w;
      TextSrcObject src = (TextSrcObject)ctx->text.source;
      XawTextPosition from, to, tmp, end = 0, *pos, *posbuf[32];
      char buf[32];
      XawTextBlock text;
      int i, spaces = MULT(ctx);
      char *lbuf = NULL, *rbuf;
      unsigned llen = 0, rlen, size;
      Bool undo = src->textSrc.enable_undo && src->textSrc.undo_state == False;
      Bool format = ctx->text.auto_fill
  	&& ctx->text.left_column < ctx->text.right_column;
  
      text.firstPos = 0;
      text.format = XawFmt8Bit;
      text.ptr = "";
  
      StartAction(ctx, event);
  
      pos = XawStackAlloc(sizeof(XawTextPosition) * src->textSrc.num_text, posbuf);
      for (i = 0; i < src->textSrc.num_text; i++)
  	pos[i] = ((TextWidget)src->textSrc.text[i])->text.insertPos;
  
      if (!GetBlockBoundaries(ctx, &from, &to)) {
  	EndAction(ctx);
  	XawStackFree(pos, posbuf);
  	return;
      }
  
      if (undo) {
  	llen = to - from;
  	end = ctx->text.lastPos;
  	lbuf = _XawTextGetText(ctx, from, to);
  	src->textSrc.undo_state = True;
      }
  
      tmp = ctx->text.lastPos;
      if (!Untabify(ctx, from, to, pos, src->textSrc.num_text, NULL)) {
  	XBell(XtDisplay(ctx), 0);
  	EndAction(ctx);
  	XawStackFree(pos, posbuf);
  	if (undo) {
  	    src->textSrc.undo_state = True;
  	    XtFree(lbuf);
  	}
  	return;
      }
      to += ctx->text.lastPos - tmp;
  
      tmp = from;
  
      if (spaces > 0) {
  	text.ptr = XawStackAlloc(spaces, buf);
  	for (i = 0; i < spaces; i++)
  	    text.ptr[i] = ' ';
  
  	text.length = spaces;
  	while (tmp < to) {
  	    _XawTextReplace(ctx, tmp, tmp, &text);
  
  	    for (i = 0; i < src->textSrc.num_text; i++)
  		if (tmp < pos[i])
  		    pos[i] += spaces;
  
  	    to += spaces;
  	    tmp = SrcScan(ctx->text.source, tmp, XawstEOL, XawsdRight, 1, True);
  	}
  	XawStackFree(text.ptr, buf);
      }
      else {
  	int min = 32767;
  
  	text.length = 0;
  	tmp = from;
  
  	/* find the amount of spaces to cut */
  	while (tmp < to) {
  	    (void)BlankLine(w, tmp, &i);
  	    if (i < min)
  		min = i;
  	    tmp = SrcScan(ctx->text.source, tmp, XawstEOL, XawsdRight, 1, True);
  	}
  	spaces = XawMin(-spaces, min);
  
  	/* cut the spaces */
  	tmp = from;
  	while (tmp < to) {
  	    _XawTextReplace(ctx, tmp, tmp + spaces, &text);
  
  	    for (i = 0; i < src->textSrc.num_text; i++)
  		if (tmp < pos[i]) {
  		    if (tmp + spaces < pos[i])
  			pos[i] -= spaces;
  		    else
  			pos[i] = tmp;
  		}
  
  	    to -= spaces;
  	    tmp = SrcScan(ctx->text.source, tmp, XawstEOL, XawsdRight, 1, True);
  	}
      }
  
      if (!format)
  	Tabify(ctx, from, to, pos, src->textSrc.num_text, NULL);
  
      if (undo) {
  	rlen = llen + (ctx->text.lastPos - end);
  	rbuf = _XawTextGetText(ctx, from, from + rlen);
  
  	text.format = _XawTextFormat(ctx);
  	size = XawTextFormat(ctx, XawFmtWide) ? sizeof(wchar_t) : sizeof(char);
  	if (llen != rlen || memcmp(lbuf, rbuf, llen * size)) {
  	    text.ptr = lbuf;
  	    text.length = llen;
  	    _XawTextReplace(ctx, from, from + rlen, &text);
  
  	    src->textSrc.undo_state = False;
  	    text.ptr = rbuf;
  	    text.length = rlen;
  	    _XawTextReplace(ctx, from, from + llen, &text);
  	}
  	else
  	    src->textSrc.undo_state = False;
  	XtFree(lbuf);
  	XtFree(rbuf);
      }
  
      for (i = 0; i < src->textSrc.num_text; i++) {
  	TextWidget tw = (TextWidget)src->textSrc.text[i];
  
  	tw->text.insertPos = XawMin(XawMax(0, pos[i]), tw->text.lastPos);
      }
      XawStackFree(pos, posbuf);
      ctx->text.showposition = True;
  
      EndAction(ctx);
  }
  
  /*ARGSUSED*/
  static void
  ToggleOverwrite(Widget w, XEvent *event, String *params, Cardinal *num_params)
  {
      TextWidget ctx = (TextWidget)w;
  
      ctx->text.overwrite = !ctx->text.overwrite;
  
      /* call information callback */
      _XawTextSetLineAndColumnNumber(ctx, True);
  }
  #endif /* OLDXAW */
  
  /*
   * Insertion Routines
   */
  static int
  InsertNewLineAndBackupInternal(TextWidget ctx)
  {
      int count, error = XawEditDone, mult = MULT(ctx);
  #ifndef OLDXAW
      XawTextPosition position;
  #endif
      XawTextBlock text;
      char buf[32];
  
      if (mult < 0) {
  	ctx->text.mult = 1;
  	return (XawEditError);
      }
  
      text.format = _XawTextFormat(ctx);
      text.length = mult;
      text.firstPos = 0;
  
      if (text.format == XawFmtWide) {
  	wchar_t *wptr;
  
  	text.ptr =  XawStackAlloc(sizeof(wchar_t) * mult, buf);
  	wptr = (wchar_t *)text.ptr;
  	for (count = 0; count < mult; count++)
  	    wptr[count] = _Xaw_atowc(XawLF);
      }
      else {
  	text.ptr = XawStackAlloc(sizeof(char) * mult, buf);
  	for (count = 0; count < mult; count++)
  	    text.ptr[count] = XawLF;
      }
  
  #ifndef OLDXAW
      position = SrcScan(ctx->text.source, ctx->text.insertPos,
  		       XawstEOL, XawsdLeft, 1, False);
  #endif
      if (_XawTextReplace(ctx, ctx->text.insertPos, ctx->text.insertPos, &text)) {
  	XBell( XtDisplay(ctx), 50);
  	error = XawEditError;
      }
      else {
  	ctx->text.showposition = TRUE;
  	ctx->text.insertPos += text.length;
      }
  
      XawStackFree(text.ptr, buf);
  
  #ifndef OLDXAW
      if (ctx->text.auto_fill && error == XawEditDone)
  	(void)FormatText(ctx, position, ctx->text.justify != XawjustifyFull,
  			 NULL, 0);
  #endif
  
      return (error);
  }
  
  /*ARGSUSED*/
  static void
  InsertNewLineAndBackup(Widget w, XEvent *event, String *p, Cardinal *n)
  {
      TextWidget ctx = (TextWidget)w;
      XawTextPosition insertPos = ctx->text.insertPos;
  
      StartAction((TextWidget)w, event);
      (void)InsertNewLineAndBackupInternal(ctx);
      ctx->text.insertPos = SrcScan(ctx->text.source, insertPos, XawstEOL,
  				  XawsdRight, 1, False);
      EndAction((TextWidget)w);
  }
  
  static int
  LocalInsertNewLine(TextWidget ctx, XEvent *event)
  {
      int error;
  
      StartAction(ctx, event);
      error = InsertNewLineAndBackupInternal(ctx);
      ctx->text.from_left = -1;
      EndAction(ctx);
  
      return (error);
  }
  
  /*ARGSUSED*/
  static void
  InsertNewLine(Widget w, XEvent *event, String *p, Cardinal *n)
  {
      (void)LocalInsertNewLine((TextWidget)w, event);
  }
  
  /*ARGSUSED*/
  static void
  InsertNewLineAndIndent(Widget w, XEvent *event, String *p, Cardinal *n)
  {
      XawTextBlock text;
      XawTextPosition pos1;
      int length;
      TextWidget ctx = (TextWidget)w;
      String line_to_ip;
  
      StartAction(ctx, event);
      pos1 = SrcScan(ctx->text.source, ctx->text.insertPos,
  		   XawstEOL, XawsdLeft, 1, False);
  
      line_to_ip = _XawTextGetText(ctx, pos1, ctx->text.insertPos);
  
      text.format = _XawTextFormat(ctx);
      text.firstPos = 0;
  
      if (text.format == XawFmtWide) {
  	wchar_t *ptr;
  
  	text.ptr = XtMalloc((2 + wcslen((wchar_t*)line_to_ip))
  			    * sizeof(wchar_t));
  	ptr = (wchar_t*)text.ptr;
  	ptr[0] = _Xaw_atowc(XawLF);
  	wcscpy((wchar_t*)++ptr, (wchar_t*)line_to_ip);
  
  	length = wcslen((wchar_t*)text.ptr);
  	while (length && (iswspace(*ptr) || *ptr == _Xaw_atowc(XawTAB)))
  	  ptr++, length--;
  	*ptr = (wchar_t)0;
  	text.length = wcslen((wchar_t*)text.ptr);
      }
      else {
  	char *ptr;
  
  	length = strlen(line_to_ip);
  	text.ptr = XtMalloc((2 + length) * sizeof(char));
  	ptr = text.ptr;
  	ptr[0] = XawLF;
  	strcpy(++ptr, line_to_ip);
  
  	length++;
  	while (length && (isspace(*ptr) || (*ptr == XawTAB)))
  	    ptr++, length--;
  	*ptr = '\0';
  	text.length = strlen(text.ptr);
      }
      XtFree(line_to_ip);
  
      if (_XawTextReplace(ctx,ctx->text.insertPos, ctx->text.insertPos, &text)) {
  	XBell(XtDisplay(ctx), 50);
  	XtFree(text.ptr);
  	EndAction(ctx);
  	return;
      }
  
      XtFree(text.ptr);
      ctx->text.from_left = -1;
      ctx->text.insertPos = SrcScan(ctx->text.source, ctx->text.old_insert,
  				  XawstPositions, XawsdRight, text.length, True);
      EndAction(ctx);
  }
  
  /*
   * Selection Routines
   */
  static void
  SelectWord(Widget w, XEvent *event, String *params, Cardinal *num_params)
  {
      TextWidget ctx = (TextWidget)w;
      XawTextPosition l, r;
  
      StartAction(ctx, event);
      l = SrcScan(ctx->text.source, ctx->text.insertPos,
  		XawstWhiteSpace, XawsdLeft, 1, False);
      r = SrcScan(ctx->text.source, l, XawstWhiteSpace, XawsdRight, 1, False);
      _XawTextSetSelection(ctx, l, r, params, *num_params);
      EndAction(ctx);
  }
  
  static void
  SelectAll(Widget w, XEvent *event, String *params, Cardinal *num_params)
  {
      TextWidget ctx = (TextWidget)w;
  
      StartAction(ctx, event);
      _XawTextSetSelection(ctx,zeroPosition,ctx->text.lastPos,params,*num_params);
      EndAction(ctx);
  }
  
  static void
  ModifySelection(TextWidget ctx, XEvent *event,
  		XawTextSelectionMode mode,
  		XawTextSelectionAction action,
  		String *params, Cardinal *num_params)
  {
  #ifndef OLDXAW
      int old_y = ctx->text.ev_y;
  #endif
  
      StartAction(ctx, event);
      NotePosition(ctx, event);
  
  #ifndef OLDXAW
      if (event->type == MotionNotify) {
  	if (ctx->text.ev_y <= ctx->text.margin.top) {
  	    if (old_y >= ctx->text.ev_y)
  		XawTextScroll(ctx, -1, 0);
  	}
  	else if (ctx->text.ev_y >= XtHeight(ctx) - ctx->text.margin.bottom) {
  	    if (old_y <= ctx->text.ev_y
  		&& !IsPositionVisible(ctx, ctx->text.lastPos))
  	      XawTextScroll(ctx, 1, 0);
  	}
      }
  #endif
      ctx->text.from_left = -1;
      _XawTextAlterSelection(ctx, mode, action, params, num_params);
  
      EndAction(ctx);
  }
  
  static void
  SelectStart(Widget w, XEvent *event, String *params, Cardinal *num_params)
  {
      TextWidget ctx = (TextWidget)w;
  
  #ifndef OLDXAW
      if (!ctx->text.selection_state) {
  	ctx->text.selection_state = True;
  #endif
  	ModifySelection(ctx, event,
  			XawsmTextSelect, XawactionStart, params, num_params);
  #ifndef OLDXAW
      }
  #endif
  }
  
  static void
  SelectAdjust(Widget w, XEvent *event, String *params, Cardinal *num_params)
  {
      TextWidget ctx = (TextWidget)w;
  
  #ifndef OLDXAW
      if (ctx->text.selection_state)
  #endif
  	ModifySelection(ctx, event, 
  			XawsmTextSelect, XawactionAdjust, params, num_params);
  }
  
  static void
  SelectEnd(Widget w, XEvent *event, String *params, Cardinal *num_params)
  {
      TextWidget ctx = (TextWidget)w;
  
  #ifndef OLDXAW
      if (ctx->text.selection_state) {
  	ctx->text.selection_state = False;
  #endif
  	ModifySelection(ctx, event,
  			XawsmTextSelect, XawactionEnd, params, num_params);
  #ifndef OLDXAW
      }
  #endif
  }
  
  static void
  ExtendStart(Widget w, XEvent *event, String *params, Cardinal *num_params)
  {
      TextWidget ctx = (TextWidget)w;
  
  #ifndef OLDXAW
      if (!ctx->text.selection_state) {
  	ctx->text.selection_state = True;
  #endif
  	ModifySelection(ctx, event,
  			XawsmTextExtend, XawactionStart, params, num_params);
  #ifndef OLDXAW
      }
  #endif
  }
  
  static void
  ExtendAdjust(Widget w, XEvent *event, String *params, Cardinal *num_params)
  {
      TextWidget ctx = (TextWidget)w;
  
  #ifndef OLDXAW
      if (ctx->text.selection_state)
  #endif
  	ModifySelection(ctx, event,
  			XawsmTextExtend, XawactionAdjust, params, num_params);
  }
  
  static void
  ExtendEnd(Widget w, XEvent *event, String *params, Cardinal *num_params)
  {
      TextWidget ctx = (TextWidget)w;
  
  #ifndef OLDXAW
      if (ctx->text.selection_state) {
  	ctx->text.selection_state = False;
  #endif
  	ModifySelection(ctx, event,
  			XawsmTextExtend, XawactionEnd, params, num_params);
  #ifndef OLDXAW
      }
  #endif
  }
  
  static void
  SelectSave(Widget  w, XEvent *event, String *params, Cardinal *num_params)
  {
      int num_atoms;
      Atom *sel;
      Display *dpy = XtDisplay(w);
      Atom selections[256];
  
      StartAction((TextWidget)w, event);
      num_atoms = *num_params;
      if (num_atoms > 256)
  	num_atoms = 256;
      for (sel=selections; --num_atoms >= 0; sel++, params++)
  	*sel = XInternAtom(dpy, *params, False);
      num_atoms = *num_params;
      _XawTextSaltAwaySelection((TextWidget)w, selections, num_atoms);
      EndAction((TextWidget)w);
  }
  
  /*
   * Misc. Routines
   */
  /*ARGSUSED*/
  static void
  SetKeyboardFocus(Widget w, XEvent *event, String *params, Cardinal *num_params)
  {
      Widget shell, parent;
  
      shell = parent = w;
      while (parent) {
  	if (XtIsShell(shell = parent))
  	    break;
  	parent = XtParent(parent);
      }
      XtSetKeyboardFocus(shell, w);
  }
  
  /*ARGSUSED*/
  static void
  RedrawDisplay(Widget w, XEvent *event, String *p, Cardinal *n)
  {
      StartAction((TextWidget)w, event);
      _XawTextClearAndCenterDisplay((TextWidget)w);
      EndAction((TextWidget)w);
  }
  
  /* This is kind of a hack, but, only one text widget can have focus at
   * a time on one display. There is a problem in the implementation of the
   * text widget, the scrollbars can not be adressed via editres, since they
   * are not children of a subclass of composite.
   * The focus variable is required to make sure only one text window will
   * show a block cursor at one time.
   */
  struct _focus { Display *display; Widget widget; };
  static struct _focus *focus;
  static Cardinal num_focus;
  
  /*ARGSUSED*/
  static void
  DestroyFocusCallback(Widget w, XtPointer user_data, XtPointer call_data)
  {
      struct _focus *f = (struct _focus*)(user_data);
  
      if (f->widget == w)
  	f->widget = NULL;
  }
  
  /*ARGSUSED*/
  static void
  TextFocusIn(Widget w, XEvent *event, String *p, Cardinal *n)
  {
      TextWidget ctx = (TextWidget)w;
      Bool display_caret = ctx->text.display_caret;
      int i;
  
      if (event->xfocus.detail == NotifyPointer)
  	return;
  
      if (event->xfocus.send_event) {
  	Window root, child;
  	int rootx, rooty, x, y;
  	unsigned int mask;
  
  	if (ctx->text.hasfocus)
  	    return;
  
  	if (XQueryPointer(XtDisplay(w), XtWindow(w), &root, &child,
  			  &rootx, &rooty, &x, &y, &mask)) {
  	    if (child)
  		return;
  	}
      }
  
      /* Let the input method know focus has arrived. */
      _XawImSetFocusValues(w, NULL, 0);
  
      if (display_caret)
  	StartAction(ctx, event);
      ctx->text.hasfocus = TRUE;
      if (display_caret)
  	EndAction(ctx);
  
      for (i = 0; i < num_focus; i++)
  	if (focus[i].display == XtDisplay(w))
  	    break;
      if (i >= num_focus) {
  	focus = (struct _focus*)
  	    XtRealloc((XtPointer)focus, sizeof(struct _focus) * (num_focus + 1));
  	i = num_focus;
  	focus[i].widget = NULL;
  	focus[i].display = XtDisplay(w);
  	num_focus++;
      }
      if (focus[i].widget != w) {
  	Widget old = focus[i].widget;
  
  	focus[i].widget = w;
  	if (old != NULL) {
  	    TextFocusOut(old, event, p, n);
  	    /* TextFocusOut may set it to NULL */
  	    focus[i].widget = w;
  	}
  	XtAddCallback(w, XtNdestroyCallback,
  		      DestroyFocusCallback, (XtPointer)&focus[i]);
      }
  }
  
  /*ARGSUSED*/
  static void
  TextFocusOut(Widget w, XEvent *event, String *p, Cardinal *n)
  {
      TextWidget ctx = (TextWidget)w;
      Bool display_caret = ctx->text.display_caret;
      Widget shell;
      Window window;
      int i, revert;
  
      shell = w;
      while (shell) {
  	if (XtIsShell(shell))
  	   break;
  	shell = XtParent(shell);
      }
  
      for (i = 0; i < num_focus; i++)
  	if (focus[i].display == XtDisplay(w))
  	    break;
      XGetInputFocus(XtDisplay(w), &window, &revert);
      if ((XtWindow(shell) == window &&
  	 (i < num_focus && focus[i].widget == w))
  	 || event->xfocus.detail == NotifyPointer)
  	return;
  
      if (i < num_focus && focus[i].widget) {
  	XtRemoveCallback(focus[i].widget, XtNdestroyCallback,
  			 DestroyFocusCallback, (XtPointer)&focus[i]);
  	focus[i].widget = NULL;
      }
  
      /* Let the input method know focus has left.*/
      _XawImUnsetFocus(w);
  
      if (display_caret)
  	StartAction(ctx, event);
      ctx->text.hasfocus = FALSE;
      if (display_caret)
  	EndAction(ctx);
  }
  
  /*ARGSUSED*/
  static void
  TextEnterWindow(Widget w, XEvent *event, String *params, Cardinal *num_params)
  {
      TextWidget ctx = (TextWidget)w;
  
      if ((event->xcrossing.detail != NotifyInferior) && event->xcrossing.focus
  	&& !ctx->text.hasfocus)
  	_XawImSetFocusValues(w, NULL, 0);
  }
  
  /*ARGSUSED*/
  static void
  TextLeaveWindow(Widget w, XEvent *event, String *params, Cardinal *num_params)
  {
      TextWidget ctx = (TextWidget)w;
  
      if ((event->xcrossing.detail != NotifyInferior) && event->xcrossing.focus
  	&& !ctx->text.hasfocus)
  	_XawImUnsetFocus(w);
  }
  
  /*
   * Function:
   *	AutoFill
   *	Arguments: ctx - The text widget.
   *
   * Description:
   *	  Breaks the line at the previous word boundry when
   *	called inside InsertChar.
   */
  static void
  AutoFill(TextWidget ctx)
  {
      int width, height, x, line_num, max_width;
      XawTextPosition ret_pos;
      XawTextBlock text;
      XRectangle cursor;
      wchar_t wc_buf[2];
  
      for (line_num = 0; line_num < ctx->text.lt.lines ; line_num++)
  	if (ctx->text.lt.info[line_num].position >= ctx->text.insertPos)
  	    break;
      if (line_num)
  	line_num--;		/* backup a line. */
  
      XawTextSinkGetCursorBounds(ctx->text.sink, &cursor);
      max_width = Max(0, (int)XtWidth(ctx) - RHMargins(ctx) - cursor.width);
  
      x = ctx->text.r_margin.left;
      XawTextSinkFindPosition(ctx->text.sink, ctx->text.lt.info[line_num].position,
  			    x, max_width, True, &ret_pos,
  			    &width, &height);
  
      if (ret_pos <= ctx->text.lt.info[line_num].position
  	|| ret_pos >= ctx->text.insertPos || ret_pos < 1)
  	return;
  
      XawTextSourceRead(ctx->text.source, ret_pos - 1, &text, 1);
  
      if (XawTextFormat(ctx, XawFmtWide)) {
  	wc_buf[0] = *(wchar_t *)text.ptr;
  	if (wc_buf[0] != _Xaw_atowc(XawSP) && wc_buf[0] != _Xaw_atowc(XawTAB))
  	    /* Only eats white spaces */
  	    return;
  
  	text.format = XawFmtWide;
  	text.ptr = (char *)wc_buf;
  	wc_buf[0] = _Xaw_atowc(XawLF);
  	wc_buf[1] = 0;
      }
      else {
  	if (text.ptr[0] != XawSP && text.ptr[0] != XawTAB)
  	    /* Only eats white spaces */
  	    return;
  
  	text.format = XawFmt8Bit;
  	text.ptr = "\n";
      }
      text.length = 1;
      text.firstPos = 0;
  
      if (_XawTextReplace(ctx, ret_pos - 1, ret_pos, &text))
  	XBell(XtDisplay((Widget)ctx), 0);
  
      if (++ctx->text.insertPos > ctx->text.lastPos)
  	ctx->text.insertPos = ctx->text.lastPos;
  }
  
  /*ARGSUSED*/
  static void
  InsertChar(Widget w, XEvent *event, String *p, Cardinal *n)
  {
      TextWidget ctx = (TextWidget)w;
      char *ptr, strbuf[128], ptrbuf[512];
      int count, error, mult = MULT(ctx);
      KeySym keysym;
      XawTextBlock text;
  #ifndef OLDXAW
      Bool format = False;
  #endif
      XawTextPosition from, to;
  
      if (XtIsSubclass (ctx->text.source, (WidgetClass) multiSrcObjectClass))
  	text.length = _XawImWcLookupString(w, &event->xkey, (wchar_t*)strbuf,
  					   sizeof(strbuf), &keysym);
      else
  	text.length = _XawLookupString(w, (XKeyEvent*)event, strbuf,
  				       sizeof(strbuf), &keysym);
  
      if (text.length == 0)
  	return;
  
      if (mult < 0) {
  	ctx->text.mult = 1;
  	return;
      }
  
      text.format = _XawTextFormat(ctx);
      if (text.format == XawFmtWide) {
  	text.ptr = ptr = XawStackAlloc(sizeof(wchar_t) * text.length
  				       * mult, ptrbuf);
  	for (count = 0; count < mult; count++) {
  	    memcpy((char*)ptr, (char *)strbuf, sizeof(wchar_t) * text.length);
  	    ptr += sizeof(wchar_t) * text.length;
  	}
  #ifndef OLDXAW
  	if (mult == 1)
  	    format = ctx->text.left_column < ctx->text.right_column;
  #endif
      }
      else {	/* == XawFmt8Bit */
  	text.ptr = ptr = XawStackAlloc(text.length * mult, ptrbuf);
  	for (count = 0; count < mult; count++) {
  	    strncpy(ptr, strbuf, text.length);
  	    ptr += text.length;
  	}
  #ifndef OLDXAW
  	if (mult == 1)
  	    format = ctx->text.left_column < ctx->text.right_column;
  #endif
      }
  
      text.length = text.length * mult;
      text.firstPos = 0;
  
      StartAction(ctx, event);
  #ifndef OLDXAW
      if (mult == 1)
  	_XawSourceSetUndoMerge((TextSrcObject)ctx->text.source, True);
  #endif
  
      from = ctx->text.insertPos;
  #ifndef OLDXAW
      if (ctx->text.overwrite) {
  	XawTextPosition tmp;
  
  	to = from + mult;
  	tmp = SrcScan(ctx->text.source, from, XawstEOL, XawsdRight, 1, False);
  	if (to > tmp)
  	    to = tmp;
      }
      else
  #endif
  	to = from;
  
      error = _XawTextReplace(ctx, from , to, &text);
  
      if (error == XawEditDone) {
  	ctx->text.from_left = -1;
  	ctx->text.insertPos = SrcScan(ctx->text.source, ctx->text.old_insert,
  				      XawstPositions, XawsdRight,
  				      text.length, True);
  	if (ctx->text.auto_fill) {
  #ifndef OLDXAW
  	    if (format)
  		(void)FormatText(ctx, SrcScan(ctx->text.source,
  					      ctx->text.insertPos, XawstEOL,
  					      XawsdLeft, 1, False), False,
  					      NULL, 0);
  	    else
  #endif
  		AutoFill(ctx);
  	}
      }
      else
  	XBell(XtDisplay(ctx), 50);
  
      XawStackFree(text.ptr, ptrbuf);
      EndAction(ctx);
  
      if (error == XawEditDone && text.format == XawFmt8Bit && text.length == 1
  	&& (text.ptr[0] == ')' || text.ptr[0] == ']' || text.ptr[0] == '}')
  	&& ctx->text.display_caret) {
  	static struct timeval tmval = {0, 500000};
  	fd_set fds;
  	Widget source = ctx->text.source;
  	XawTextPosition insertPos = ctx->text.insertPos, pos, tmp, last;
  	char left, right = text.ptr[0];
  	int level = 0;
  	XtAppContext app_context = XtWidgetToApplicationContext(w);
  
  	left = right == ')' ? '(' : right == ']' ? '[' : '{';
  
  	last = insertPos - 1;
  	do {
  	    text.ptr[0] = left;
  	    pos = XawTextSourceSearch(source, last, XawsdLeft, &text);
  	    if (pos == XawTextSearchError || !IsPositionVisible(ctx, pos))
  		return;
  	    text.ptr[0] = right;
  	    tmp = pos;
  	    do {
  		tmp = XawTextSourceSearch(source, tmp, XawsdRight, &text);
  		if (tmp == XawTextSearchError)
  		    return;
  		if (tmp <= last)
  		    ++level;
  	    } while (++tmp <= last);
  	    --level;
  	    last = pos;
  	} while (level);
  
  	StartAction(ctx, NULL);
  #ifndef OLDXAW
  	_XawSourceSetUndoMerge((TextSrcObject)ctx->text.source, True);
  #endif
  	ctx->text.insertPos = pos;
  	EndAction(ctx);
  
  	XSync(XtDisplay(w), False);
  	while (XtAppPending(app_context) & XtIMXEvent) {
  	    XEvent ev;
  	    if (! XtAppPeekEvent(app_context, &ev))
  		break;
  	    if (ev.type == KeyPress || ev.type == ButtonPress)
  		break;
  	    XtAppProcessEvent(app_context, XtIMXEvent);
  	}
  	FD_ZERO(&fds);
  	FD_SET(ConnectionNumber(XtDisplay(w)), &fds);
  	(void)select(FD_SETSIZE, &fds, NULL, NULL, &tmval);
  	if (tmval.tv_usec != 500000)
  	    usleep(40000);
  
  	StartAction(ctx, NULL);
  #ifndef OLDXAW
  	_XawSourceSetUndoMerge((TextSrcObject)ctx->text.source, True);
  #endif
  	ctx->text.insertPos = insertPos;
  	EndAction(ctx);
      }
  }
  
  /* IfHexConvertHexElseReturnParam() - called by InsertString
   *
   * i18n requires the ability to specify multiple characters in a hexa-
   * decimal string at once.  Since Insert was already too long, I made
   * this a seperate routine.
   *
   * A legal hex string in MBNF: '0' 'x' ( HEX-DIGIT HEX-DIGIT )+ '\0'
   *
   * WHEN:    the passed param is a legal hex string
   * RETURNS: a pointer to that converted, null terminated hex string;
   *	    len_return holds the character count of conversion result
   *
   * WHEN:    the passed param is not a legal hex string:
   * RETURNS: the parameter passed;
   *	    len_return holds the char count of param.
   *
   * NOTE:    In neither case will there be strings to free. */
  static char *
  IfHexConvertHexElseReturnParam(char *param, int *len_return)
  {
      char *p;	    	/* steps through param char by char */
      char c;	    	/* holds the character pointed to by p */
      int ind;		/* steps through hexval buffer char by char */
      static char hexval[XawTextActionMaxHexChars];
      Boolean first_digit;
  
      /* reject if it doesn't begin with 0x and at least one more character. */
      if ((param[0] != '0') || (param[1] != 'x') || (param[2] == '\0')) {
  	*len_return = strlen(param);
  	return(param);
      }
  
      /* Skip the 0x; go character by character shifting and adding. */
      first_digit = True;
      ind = 0;
      hexval[ind] = '\0';
  
      for (p = param+2; (c = *p) != '\0'; p++) {
  	hexval[ind] *= 16;
  	if (c >= '0' && c <= '9')
  	    hexval[ind] += c - '0';
  	else if (c >= 'a' && c <= 'f')
  	    hexval[ind] += c - 'a' + 10;
  	else if (c >= 'A' && c <= 'F')
  	    hexval[ind] += c - 'A' + 10;
  	else
  	    break;
  
  	/* If we didn't break in preceding line, it was a good hex char. */
  	if (first_digit)
  	    first_digit = False;
  	else {
  	    first_digit = True;
  	    if (++ind < XawTextActionMaxHexChars)
  		hexval[ind] = '\0';
  	    else {
  		*len_return = strlen(param);
  		return(param);
  	    }
  	}
      }
  
      /* We quit the above loop becasue we hit a non hex.  If that char is \0... */
      if ((c == '\0') && first_digit) {
  	*len_return = strlen(hexval);
  	return (hexval);       /* ...it was a legal hex string, so return it */
      }
  
      /* Else, there were non-hex chars or odd digit count, so... */
  
      *len_return = strlen(param);
      return (param);			   /* ...return the verbatim string. */
  }
  
  /* InsertString() - action
   *
   * Mostly rewritten for R6 i18n.
   *
   * Each parameter, in turn, will be insert at the inputPos
   * and the inputPos advances to the insertion's end.
   *
   * The exception is that parameters composed of the two
   * characters 0x, followed only by an even number of
   * hexadecimal digits will be converted to characters */
  /*ARGSUSED*/
  static void
  InsertString(Widget w, XEvent *event, String *params, Cardinal *num_params)
  {
      TextWidget ctx = (TextWidget)w;
      XtAppContext app_con = XtWidgetToApplicationContext(w);
      XawTextBlock text;
      int i;
  
      text.firstPos = 0;
      text.format = _XawTextFormat(ctx);
  
      StartAction(ctx, event);
      for (i = *num_params; i; i--, params++) {	/* DO FOR EACH PARAMETER */
  	text.ptr = IfHexConvertHexElseReturnParam(*params, &text.length);
  
  	if (text.length == 0)
  	    continue;
  
  	if (XawTextFormat(ctx, XawFmtWide)) {	/* convert to WC */
  	    int temp_len;
  
  	    text.ptr = (char*)_XawTextMBToWC(XtDisplay(w), text.ptr,
  					     &text.length);
  
  	    if (text.ptr == NULL) {	  /* conversion error */
  		XtAppWarningMsg(app_con,
  				"insertString", "textAction", "XawError",
  				"insert-string()'s parameter contents "
  				"not legal in this locale.",
  				NULL, NULL);
  		ParameterError(w, *params);
  		continue;
  	   }
  
  	    /* Double check that the new input is legal: try to convert to MB. */
  
  	    temp_len = text.length;	 /* _XawTextWCToMB's 3rd arg is in_out */
  	    if (_XawTextWCToMB(XtDisplay(w), (wchar_t*)text.ptr, &temp_len)
  		== NULL) {
  		XtAppWarningMsg( app_con,
  				 "insertString", "textAction", "XawError",
  				 "insert-string()'s parameter contents "
  				 "not legal in this locale.",
  				 NULL, NULL);
  		ParameterError(w, *params);
  		continue;
  	    }
  	} /* convert to WC */
  
  	if (_XawTextReplace(ctx, ctx->text.insertPos,
  			    ctx->text.insertPos, &text)) {
  	    XBell(XtDisplay(ctx), 50);
  	    EndAction(ctx);
  	    return;
  	}
  
  	ctx->text.from_left = -1;
  	/* Advance insertPos to the end of the string we just inserted. */
  	ctx->text.insertPos = SrcScan(ctx->text.source, ctx->text.old_insert,
  				       XawstPositions, XawsdRight, text.length,
  				      True);
  
      } /* DO FOR EACH PARAMETER */
  
      EndAction(ctx);
  }
  
  /* DisplayCaret() - action
   * 
   * The parameter list should contain one boolean value.  If the
   * argument is true, the cursor will be displayed.  If false, not.
   *
   * The exception is that EnterNotify and LeaveNotify events may
   * have a second argument, "always".  If they do not, the cursor
   * is only affected if the focus member of the event is true.	*/
  static void
  DisplayCaret(Widget w, XEvent *event, String *params, Cardinal *num_params)
  {
      TextWidget ctx = (TextWidget)w;
      Bool display_caret = True;
  
      if	((event->type == EnterNotify || event->type == LeaveNotify)
  	 && ((*num_params >= 2) && (strcmp(params[1], "always") == 0))
  	 && (!event->xcrossing.focus))
  	return;
  
      if (*num_params > 0) {	/* default arg is "True" */
  	XrmValue from, to;
  	from.size = strlen(from.addr = params[0]);
  	XtConvert(w, XtRString, &from, XtRBoolean, &to);
  
  	if (to.addr != NULL)
  	    display_caret = *(Boolean*)to.addr;
  	if (ctx->text.display_caret == display_caret)
  	    return;
      }
      StartAction(ctx, event);
      ctx->text.display_caret = display_caret;
      EndAction(ctx);
  }
  
  #ifndef OLDXAW
  static void
  Numeric(Widget w, XEvent *event, String *params, Cardinal *num_params)
  {
      TextWidget ctx = (TextWidget)w;
  
      if (ctx->text.numeric) {
  	long mult = ctx->text.mult;
  
  	if (*num_params != 1 || strlen(params[0]) != 1
  	    || (!isdigit(params[0][0])
  		&& (params[0][0] != '-' || mult != 0))) {
  	    char err_buf[256];
  
  	    if (event && (event->type == KeyPress || event->type == KeyRelease)
  		&& params[0][0] == '-') {
  		InsertChar(w, event, params, num_params);
  		return;
  	    }
  	    XmuSnprintf(err_buf, sizeof(err_buf),
  			"numeric: Invalid argument%s'%s'",
  			*num_params ? ", " : "", *num_params ? params[0] : "");
  	    XtAppWarning(XtWidgetToApplicationContext(w), err_buf);
  	    ctx->text.numeric = False;
  	    ctx->text.mult = 1;
  	    return;
  	}
  	if (params[0][0] == '-') {
  	    ctx->text.mult = 32767;
  	    return;
  	}
  	else if (mult == 32767) {
  	    mult = ctx->text.mult = - (params[0][0] - '0');
  	    return;
  	}
  	else {
  	    mult = mult * 10 + (params[0][0] - '0') * (mult < 0 ? -1 : 1);
  	    ctx->text.mult = ctx->text.mult * 10 + (params[0][0] - '0') *
  			     (mult < 0 ? -1 : 1);
  	}
  	if (mult != ctx->text.mult || mult >= 32767) {	/* checks for overflow */
  	    XBell(XtDisplay(w), 0);
  	    ctx->text.mult = 1;
  	    ctx->text.numeric = False;
  	    return;
  	}
      }
      else
  	InsertChar(w, event, params, num_params);
  }
  
  /*ARGSUSED*/
  static void
  KeyboardReset(Widget w, XEvent *event, String *params, Cardinal *num_params)
  {
      TextWidget ctx = (TextWidget)w;
  
      ctx->text.numeric = False;
      ctx->text.mult = 1;
  
      (void)_XawTextSrcToggleUndo((TextSrcObject)ctx->text.source);
  
      if (ctx->text.kill_ring_ptr) {
  	--ctx->text.kill_ring_ptr->refcount;
  	ctx->text.kill_ring_ptr = NULL;
      }
      ctx->text.kill_ring = 0;
  
      XBell(XtDisplay(w), 0);
  }
  #endif /* OLDXAW */
  
  /* Multiply() - action
   *
   * The parameter list may contain either a number or the string 'Reset'.
   *
   * A number will multiply the current multiplication factor by that number.
   * Many of the text widget actions will will perform n actions, where n is
   * the multiplication factor.
   *
   * The string reset will reset the mutiplication factor to 1. */
  /*ARGSUSED*/
  static void
  Multiply(Widget w, XEvent *event, String *params, Cardinal *num_params)
  {
      TextWidget ctx = (TextWidget)w;
      int mult;
  
      if (*num_params != 1) {
  	XtAppError(XtWidgetToApplicationContext(w),
  		   "Xaw Text Widget: multiply() takes exactly one argument.");
  	XBell(XtDisplay(w), 0);
  	return;
      }
  
      if ((params[0][0] == 'r') || (params[0][0] == 'R')) {
  	XBell(XtDisplay(w), 0);
  #ifndef OLDXAW
  	ctx->text.numeric = False;
  #endif
  	ctx->text.mult = 1;
  	return;
      }
  
  #ifndef OLDXAW
      if (params[0][0] == 's' || params[0][0] == 'S') {
  	ctx->text.numeric = True;
   	ctx->text.mult = 0;
  	return;
      }
      else
  #endif
  	if ((mult = atoi(params[0])) == 0) {
  	char buf[BUFSIZ];
  
  	XmuSnprintf(buf, sizeof(buf),
  		    "%s %s", "Xaw Text Widget: multiply() argument",
  		    "must be a number greater than zero, or 'Reset'.");
  	XtAppError(XtWidgetToApplicationContext(w), buf);
  	XBell(XtDisplay(w), 50);
  	return;
      }
  
      ctx->text.mult *= mult;
  }
  
  /* StripOutOldCRs() - called from FormRegion
   *
   * removes CRs in widget ctx, from from to to.
   *
   * RETURNS: the new ending location (we may add some characters),
   * or XawReplaceError if the widget can't be written to. */
  static XawTextPosition
  StripOutOldCRs(TextWidget ctx, XawTextPosition from, XawTextPosition to,
  	       XawTextPosition *pos, int num_pos)
  {
      XawTextPosition startPos, endPos, eop_begin, eop_end, temp;
      Widget src = ctx->text.source;
      XawTextBlock text;
      char *buf;
      static wchar_t wc_two_spaces[3];
      int idx;
  
      /* Initialize our TextBlock with two spaces. */
      text.firstPos = 0;
      text.format = _XawTextFormat(ctx);
      if (text.format == XawFmt8Bit)
        text.ptr= "  ";
      else {
  	wc_two_spaces[0] = _Xaw_atowc(XawSP);
  	wc_two_spaces[1] = _Xaw_atowc(XawSP);
  	wc_two_spaces[2] = 0;
  	text.ptr = (char*)wc_two_spaces;
      }
  
      /* Strip out CR's. */
      eop_begin = eop_end = startPos = endPos = from;
  
      /* CONSTCOND */
      while (TRUE) {
  	endPos=SrcScan(src, startPos, XawstEOL, XawsdRight, 1, False);
  
  	temp = SrcScan(src, endPos, XawstWhiteSpace, XawsdLeft, 1, False);
  	temp = SrcScan(src, temp,   XawstWhiteSpace, XawsdRight,1, False);
  
  	if (temp > startPos)
  	    endPos = temp;
  
  	if (endPos >= to)
  	    break;
  
  	if (endPos >= eop_begin) {
  	    startPos = eop_end;
  	    eop_begin=SrcScan(src, startPos, XawstParagraph,
  			      XawsdRight, 1,False);
  	    eop_end = SrcScan(src, startPos, XawstParagraph,
  			      XawsdRight, 1, True);
  	}
  	else {
  	    XawTextPosition periodPos, next_word;
  	    int i, len;
  
  	    periodPos = SrcScan(src, endPos, XawstPositions,
  				XawsdLeft, 1, True);
  	    next_word = SrcScan(src, endPos, XawstWhiteSpace,
  				XawsdRight, 1, False);
  
  	    len = next_word - periodPos;
  
  	    text.length = 1;
  	    buf = _XawTextGetText(ctx, periodPos, next_word);
  	    if (text.format == XawFmtWide) {
  		if (periodPos < endPos && ((wchar_t*)buf)[0] == _Xaw_atowc('.'))
  		  text.length++;
  	    }
  	    else
  		if (periodPos < endPos && buf[0] == '.')
  		    text.length++;	  /* Put in two spaces. */
  
  	    /*
  	     * Remove all extra spaces.
  	     */
  	    for (i = 1 ; i < len; i++) 
  		if (text.format ==  XawFmtWide) {
  		    if (!iswspace(((wchar_t*)buf)[i]) || ((periodPos + i) >= to))
  			break;
  		}
  		else if (!isspace(buf[i]) || (periodPos + i) >= to)
  		    break;
        
  	    XtFree(buf);
  
  	    to -= (i - text.length - 1);
  	    startPos = SrcScan(src, periodPos, XawstPositions,
  			       XawsdRight, i, True);
  	    if (_XawTextReplace(ctx, endPos, startPos, &text) != XawEditDone)
  		return (XawReplaceError);
  
  	    for (idx = 0; idx < num_pos; idx++) {
  		if (endPos < pos[idx]) {
  		    if (startPos < pos[idx])
  			pos[idx] -= startPos - endPos;
  		    else
  			pos[idx] = endPos;
  		    pos[idx] += text.length;
  		}
  	    }
  
  	    startPos -= i - text.length;
  	}
      }
  
      return (to);
  }
  
  /* InsertNewCRs() - called from FormRegion
   *
   * inserts new CRs for FormRegion, thus for FormParagraph action */
  static void
  InsertNewCRs(TextWidget ctx, XawTextPosition from, XawTextPosition to,
  	     XawTextPosition *pos, int num_pos)
  {
      XawTextPosition startPos, endPos, space, eol;
      XawTextBlock text;
      int i, width, height, len, wwidth, idx;
      char *buf;
      static wchar_t wide_CR[2];
  
      text.firstPos = 0;
      text.length = 1;
      text.format = _XawTextFormat(ctx);
  
      if (text.format == XawFmt8Bit)
  	text.ptr = "\n";
      else {
  	wide_CR[0] = _Xaw_atowc(XawLF);
  	wide_CR[1] = 0;
  	text.ptr = (char*)wide_CR;
      }
  
      startPos = from;
  
      wwidth = (int)XtWidth(ctx) - (int)HMargins(ctx);
      if (ctx->text.wrap != XawtextWrapNever) {
  	XRectangle cursor;
  
  	XawTextSinkGetCursorBounds(ctx->text.sink, &cursor);
  	wwidth -= (int)cursor.width;
      }
      wwidth = XawMax(0, wwidth);
  
      /* CONSTCOND */
      while (TRUE) {
  	XawTextSinkFindPosition(ctx->text.sink, startPos,
  				(int)ctx->text.r_margin.left, wwidth,
  				True, &eol, &width, &height);
  	if (eol == startPos)
  	    ++eol;
  	if (eol >= to)
  	    break;
  
  	eol = SrcScan(ctx->text.source, eol, XawstPositions,
  		      XawsdLeft, 1, True);
  	space = SrcScan(ctx->text.source, eol, XawstWhiteSpace,
  			XawsdRight,1, True);
  
  	startPos = endPos = eol;
  	if (eol == space) 
  	    return;
  
  	len = (int)(space - eol);
  	buf = _XawTextGetText(ctx, eol, space);
  	for (i = 0 ; i < len ; i++)
  	    if (text.format == XawFmtWide) {
  		if (!iswspace(((wchar_t*)buf)[i]))
  		    break;
  	    }
  	    else if (!isspace(buf[i]))
  		break;
  
  	to -= (i - 1);
  	endPos = SrcScan(ctx->text.source, endPos,
  			 XawstPositions, XawsdRight, i, True);
  	XtFree(buf);
  
  	if (_XawTextReplace(ctx, startPos, endPos, &text))
  	    return;
  
  	for (idx = 0; idx < num_pos; idx++) {
  	    if (startPos < pos[idx]) {
  		if (endPos < pos[idx])
  		    pos[idx] -= endPos - startPos;
  		else
  		    pos[idx] = startPos;
  		pos[idx] += text.length;
  	    }
  	}
  
  	startPos = SrcScan(ctx->text.source, startPos,
  			   XawstPositions, XawsdRight, 1, True);
      }
  }
  
  /* FormRegion() - called by FormParagraph
   *
   * oversees the work of paragraph-forming a region
   *
   * Return:
   *	XawEditDone if successful, or XawReplaceError
   */
  static int
  FormRegion(TextWidget ctx, XawTextPosition from, XawTextPosition to,
  	   XawTextPosition *pos, int num_pos)
  {
  #ifndef OLDXAW
      Bool format = ctx->text.auto_fill
  	&& ctx->text.left_column < ctx->text.right_column;
  #endif
  
      if (from >= to)
  	return (XawEditDone);
  
  #ifndef OLDXAW
      if (format) {
  	XawTextPosition len = ctx->text.lastPos;
  	int inc = 0;
  
  	if (ctx->text.justify == XawjustifyLeft ||
  	    ctx->text.justify == XawjustifyFull) {
  	    Untabify(ctx, from, to, pos, num_pos, NULL);
  	    to += ctx->text.lastPos - len;
  	    len = ctx->text.insertPos;
  	    (void)BlankLine((Widget)ctx, from, &inc);
  	    if (from + inc >= to)
  		return (XawEditDone);
  	}
  	if (!StripSpaces(ctx, from + inc, to, pos, num_pos, NULL))
  	    return (XawReplaceError);
  	to += ctx->text.lastPos - len;
  
  	FormatText(ctx, from, ctx->text.justify != XawjustifyFull, pos, num_pos);
      }
      else {
  #endif
  	if ((to = StripOutOldCRs(ctx, from, to, pos, num_pos)) == XawReplaceError)
  	    return (XawReplaceError);
  	InsertNewCRs(ctx, from, to, pos, num_pos);
  #ifndef OLDXAW
      }
  #endif
      ctx->text.from_left = -1;
  
      return (XawEditDone);
  }
  
  #ifndef OLDXAW
  static Bool
  BlankLine(Widget w, XawTextPosition pos, int *blanks_return)
  {
      int i, blanks = 0;
      XawTextBlock block;
      Widget src = XawTextGetSource(w);
      XawTextPosition l = SrcScan(src, pos, XawstEOL, XawsdLeft, 1, False);
      XawTextPosition r = SrcScan(src, pos, XawstEOL, XawsdRight, 1, False);
  
      while (l < r) {
  	l = XawTextSourceRead(src, l, &block, r - l);
  	if (block.length == 0) {
  	    if (blanks_return)
  		*blanks_return = blanks;
  	    return (True);
  	}
  	if (XawTextFormat((TextWidget)w, XawFmt8Bit)) {
  	    for (i = 0; i < block.length; i++, blanks++)
  		if (block.ptr[i] != ' ' &&
  		    block.ptr[i] != '\t') {
  		    if (blanks_return)
  			*blanks_return = blanks;
  		    return (block.ptr[i] == '\n');
  		}
  	}
  	else if (XawTextFormat((TextWidget)w, XawFmtWide)) {
  	    for (i = 0; i < block.length; i++, blanks++)
  		if (_Xaw_atowc(XawSP) != ((wchar_t*)block.ptr)[i] &&
  		    _Xaw_atowc(XawTAB) != ((wchar_t*)block.ptr)[i]) {
  		    if (blanks_return)
  			*blanks_return = blanks;
  		    return (_Xaw_atowc(XawLF) == ((wchar_t*)block.ptr)[i]);
  		}
  	}
      }
  
      return (True);
  }
  
  static Bool
  GetBlockBoundaries(TextWidget ctx,
  		   XawTextPosition *from_return, XawTextPosition *to_return)
  {
      XawTextPosition from, to;
  
      if (ctx->text.auto_fill && ctx->text.left_column < ctx->text.right_column) {
  	if (ctx->text.s.left != ctx->text.s.right) {
  	    from = SrcScan(ctx->text.source,
  			   XawMin(ctx->text.s.left, ctx->text.s.right),
  			   XawstEOL, XawsdLeft, 1, False);
  	    to   = SrcScan(ctx->text.source,
  			   XawMax(ctx->text.s.right, ctx->text.s.right),
  			   XawstEOL, XawsdRight, 1, False);
  	}
  	else {
  	    XawTextBlock block;
  	    XawTextPosition tmp;
  	    Bool first;
  
  	    from = to = ctx->text.insertPos;
  
  	    /* find from position */
  	    first = True;
  	    while (1) {
  		tmp = from;
  		from = SrcScan(ctx->text.source, from, XawstEOL, XawsdLeft,
  			       1 + !first, False);
  		XawTextSourceRead(ctx->text.source, from, &block, 1);
  		if (block.length == 0 ||
  		    (XawTextFormat(ctx, XawFmt8Bit) &&
  		     block.ptr[0] != ' ' &&
  		     block.ptr[0] != '\t' &&
  		     !isalnum(*(unsigned char*)block.ptr)) ||
  		    (XawTextFormat(ctx, XawFmtWide) &&
  		     _Xaw_atowc(XawSP) != *(wchar_t*)block.ptr &&
  		     _Xaw_atowc(XawTAB) != *(wchar_t*)block.ptr &&
  		     !iswalnum(*(wchar_t*)block.ptr)) ||
  		    BlankLine((Widget)ctx, from, NULL)) {
  		    from = tmp;
  		    break;
  		}
  		if (from == tmp && !first)
  		    break;
  		first = False;
  	    }
  	    if (first)
  		return (False);
  
  	    /* find to position */
  	    first = True;
  	    while (1) {
  		tmp = to;
  		to = SrcScan(ctx->text.source, to, XawstEOL, XawsdRight,
  			     1 + !first, False);
  		XawTextSourceRead(ctx->text.source, to + (to < ctx->text.lastPos),
  				  &block, 1);
  		if (block.length == 0 ||
  		    (XawTextFormat(ctx, XawFmt8Bit) &&
  		     block.ptr[0] != ' ' &&
  		     block.ptr[0] != '\t' &&
  		     !isalnum(*(unsigned char*)block.ptr)) ||
  		    (XawTextFormat(ctx, XawFmtWide) &&
  		     _Xaw_atowc(XawSP) != *(wchar_t*)block.ptr &&
  		     _Xaw_atowc(XawTAB) != *(wchar_t*)block.ptr &&
  		     !iswalnum(*(wchar_t*)block.ptr)) ||
  		    BlankLine((Widget)ctx, to, NULL))
  		    break;
  		if (to == tmp && !first)
  		    break;
  		first = False;
  	    }
  	}
      }
      else {
  	from = SrcScan(ctx->text.source, ctx->text.insertPos, XawstEOL,
  		       XawsdLeft, 1, False);
  	if (BlankLine((Widget)ctx, from, NULL))
  	    return (False);
  	from = SrcScan(ctx->text.source, from, XawstParagraph,
  		       XawsdLeft, 1, False);
  	if (BlankLine((Widget)ctx, from, NULL))
  	    from = SrcScan(ctx->text.source, from, XawstEOL,
  			   XawsdRight, 1, True);
  	to = SrcScan(ctx->text.source, from, XawstParagraph,
  			XawsdRight, 1, False);
      }
  
      if (from < to) {
  	*from_return = from;
  	*to_return = to;
  	return (True);
      }
  
      return (False);
  }
  #endif /* OLDXAW */
  
  /* FormParagraph() - action
   *
   * removes and reinserts CRs to maximize line length without clipping */
  /*ARGSUSED*/
  static void
  FormParagraph(Widget w, XEvent *event, String *params, Cardinal *num_params)
  {
      TextWidget ctx = (TextWidget)w;
      XawTextPosition from, to, buf[32], *pos;
  #ifndef OLDXAW
      XawTextPosition endPos = 0;
      char *lbuf = NULL, *rbuf;
      TextSrcObject src = (TextSrcObject)ctx->text.source;
      Cardinal i;
      Bool undo = src->textSrc.enable_undo && src->textSrc.undo_state == False;
  #endif
  
      StartAction(ctx, event);
  
  #ifndef OLDXAW
      pos = XawStackAlloc(sizeof(XawTextPosition) * src->textSrc.num_text, buf);
      for (i = 0; i < src->textSrc.num_text; i++)
  	pos[i] = ((TextWidget)src->textSrc.text[i])->text.old_insert;
  #else
      pos = buf;
      *pos = ctx->text.old_insert;
  #endif
  
  #ifndef OLDXAW
      if (!GetBlockBoundaries(ctx, &from, &to)) {
  	EndAction(ctx);
  	XawStackFree(pos, buf);
  	return;
      }
  
      if (undo) {
  	src->textSrc.undo_state = True;
  	lbuf = _XawTextGetText(ctx, from, to);
  	endPos = ctx->text.lastPos;
      }
  
      if (FormRegion(ctx, from, to, pos, src->textSrc.num_text) == XawReplaceError) {
  #else
      from =  SrcScan(ctx->text.source, ctx->text.insertPos,
  		    XawstParagraph, XawsdLeft, 1, False);
      to  =   SrcScan(ctx->text.source, from,
  		    XawstParagraph, XawsdRight, 1, False);
  
      if (FormRegion(ctx, from, to, pos, 1) == XawReplaceError) {
  #endif
  	XawStackFree(pos, buf);
  	XBell(XtDisplay(w), 0);
  #ifndef OLDXAW
  	if (undo) {
  	    src->textSrc.undo_state = False;
  	    XtFree(lbuf);
  	}
  #endif
      }
  #ifndef OLDXAW
      else if (undo) {
  	/* makes the form-paragraph only one undo/redo step */
  	unsigned llen, rlen, size;
  	XawTextBlock block;
  
  	llen = to - from;
  	rlen = llen + (ctx->text.lastPos - endPos);
  
  	block.firstPos = 0;
  	block.format = _XawTextFormat(ctx);
  
  	rbuf = _XawTextGetText(ctx, from, from + rlen);
  
  	size = XawTextFormat(ctx, XawFmtWide) ? sizeof(wchar_t) : sizeof(char);
  	if (llen != rlen || memcmp(lbuf, rbuf, llen * size)) {
  	    block.ptr = lbuf;
  	    block.length = llen;
  	    _XawTextReplace(ctx, from, from + rlen, &block);
  
  	    src->textSrc.undo_state = False;
  	    block.ptr = rbuf;
  	    block.length = rlen;
  	    _XawTextReplace(ctx, from, from + llen, &block);
  	}
  	else
  	    src->textSrc.undo_state = False;
  	XtFree(lbuf);
  	XtFree(rbuf);
      }
  
      for (i = 0; i < src->textSrc.num_text; i++) {
  	TextWidget tw = (TextWidget)src->textSrc.text[i];
  
  	tw->text.old_insert = tw->text.insertPos = pos[i];
  	_XawTextBuildLineTable(tw, SrcScan((Widget)src, tw->text.lt.top, XawstEOL,
  			       XawsdLeft, 1, False), False);
  	tw->text.clear_to_eol = True;
      }
  #else
      ctx->text.old_insert = ctx->text.insertPos = *pos;
      _XawTextBuildLineTable(ctx, SrcScan(ctx->text.source, ctx->text.lt.top,
  			   XawstEOL, XawsdLeft, 1, False), False);
      ctx->text.clear_to_eol = True;
  #endif
      XawStackFree(pos, buf);
      ctx->text.showposition = True;
  
      EndAction(ctx);
  }
  
  /* TransposeCharacters() - action
   *
   * Swaps the character to the left of the mark
   * with the character to the right of the mark */
  /*ARGSUSED*/
  static void
  TransposeCharacters(Widget w, XEvent *event,
  		    String *params, Cardinal *num_params)
  {
      TextWidget ctx = (TextWidget)w;
      XawTextPosition start, end;
      XawTextBlock text;
      char *buf;
      int i, mult = MULT(ctx);
  
      if (mult < 0) {
  	ctx->text.mult = 1;
  	return;
      }
  
      StartAction(ctx, event);
  
      /* Get bounds. */
  
      start = SrcScan(ctx->text.source, ctx->text.insertPos, XawstPositions,
  		    XawsdLeft, 1, True);
      end = SrcScan(ctx->text.source, ctx->text.insertPos, XawstPositions,
  		  XawsdRight, mult, True);
  
      /* Make sure we aren't at the very beginning or end of the buffer. */
  
      if (start == ctx->text.insertPos || end == ctx->text.insertPos) {
  	XBell(XtDisplay(w), 0);   /* complain. */
  	EndAction(ctx);
  	return;
      }
  
      ctx->text.from_left = -1;
      ctx->text.insertPos = end;
  
      text.firstPos = 0;
      text.format = _XawTextFormat(ctx);
  
      /* Retrieve text and swap the characters. */
      if (text.format == XawFmtWide) {
  	wchar_t wc;
  	wchar_t *wbuf;
  
  	wbuf = (wchar_t*)_XawTextGetText(ctx, start, end);
  	text.length = wcslen(wbuf);
  	wc = wbuf[0];
  	for (i = 1; i < text.length; i++)
  	    wbuf[i - 1] = wbuf[i];
  	wbuf[i - 1] = wc;
  	buf = (char*)wbuf; /* so that it gets assigned and freed */
      }
      else {	/* thus text.format == XawFmt8Bit */
  	char c;
  
  	buf = _XawTextGetText(ctx, start, end);
  	text.length = strlen(buf);
  	c = buf[0];
  	for (i = 1; i < text.length; i++)
  	    buf[i - 1] = buf[i];
  	buf[i - 1] = c;
      }
  
      text.ptr = buf;
  
      /* Store new text in source. */
  
      if (_XawTextReplace (ctx, start, end, &text))
  	XBell(XtDisplay(w), 0);
      XtFree((char *)buf);
      EndAction(ctx);
  }
  
  #ifndef OLDXAW
  /*ARGSUSED*/
  static void
  Undo(Widget w, XEvent *event, String *params, Cardinal *num_params)
  {
      TextWidget ctx = (TextWidget)w;
      int mul = MULT(ctx);
      Bool toggle = False;
  
      if (mul < 0) {
  	toggle = True;
  	_XawTextSrcToggleUndo((TextSrcObject)ctx->text.source);
  	ctx->text.mult = mul = -mul;
      }
  
      StartAction(ctx, event);
      for (; mul; --mul)
  	if (!_XawTextSrcUndo((TextSrcObject)ctx->text.source, &ctx->text.insertPos))
  	    break;
      ctx->text.showposition = True;
  
      if (toggle)
  	_XawTextSrcToggleUndo((TextSrcObject)ctx->text.source);
      EndAction(ctx);
  }
  #endif
  
  /* NoOp() - action
   * This action performs no action, and allows the user or
   * application programmer to unbind a translation.
   *
   * Note: If the parameter list contains the string "RingBell" then
   *	 this action will ring the bell.
   */
  /*ARGSUSED*/
  static void
  NoOp(Widget w, XEvent *event, String *params, Cardinal *num_params)
  {
      if (*num_params != 1)
  	return;
  
      switch(params[0][0]) {
  	case 'R':
  	case 'r':
  	    XBell(XtDisplay(w), 0);
  	    /*FALLTROUGH*/
  	default:
  	    break;
      }
  }
  
  /* Reconnect() - action
   * This reconnects to the input method.  The user will typically call
   * this action if/when connection has been severed, or when the app
   * was started up before an IM was started up
   */
  /*ARGSUSED*/
  static void
  Reconnect(Widget w, XEvent *event, String *params, Cardinal *num_params)
  {
      _XawImReconnect(w);
  }
  
  #define	CAPITALIZE	1
  #define	DOWNCASE	2
  #define UPCASE		3
  
  #ifdef NO_LIBC_I18N
  static int
  ToLower(int ch)
  {
      char buf[2];
  
      *buf = ch;
      XmuNCopyISOLatin1Lowered(buf, buf, sizeof(buf));
  
      return (*buf);
  }
  
  static int
  ToUpper(int ch)
  {
      char buf[2];
  
      *buf = ch;
      XmuNCopyISOLatin1Uppered(buf, buf, sizeof(buf));
  
      return (*buf);
  }
  
  static int
  IsAlnum(int ch)
  {
      return ((ch >= '0' && ch <= '9') || ToUpper(ch) != ch || ToLower(ch) != ch);
  }
  
  static int
  IsLower(int ch)
  {
      char upbuf[2];
      char lobuf[2];
  
      *upbuf = *lobuf = ch;
      XmuNCopyISOLatin1Lowered(lobuf, lobuf, sizeof(lobuf));
      XmuNCopyISOLatin1Uppered(upbuf, upbuf, sizeof(upbuf));
  
      return (*lobuf != *upbuf && ch == *lobuf);
  }
  
  static int
  IsUpper(int ch)
  {
      char upbuf[2];
      char lobuf[2];
  
      *upbuf = *lobuf = ch;
      XmuNCopyISOLatin1Lowered(lobuf, lobuf, sizeof(lobuf));
      XmuNCopyISOLatin1Uppered(upbuf, upbuf, sizeof(upbuf));
  
      return (*lobuf != *upbuf && ch == *upbuf);
  }
  #else
  #define	ToLower	tolower
  #define ToUpper	toupper
  #define IsAlnum isalnum
  #define IsLower islower
  #define IsUpper isupper
  #endif
  
  static void
  CaseProc(Widget w, XEvent *event, int cmd)
  {
      TextWidget ctx = (TextWidget)w;
      short mul = MULT(ctx);
      XawTextPosition left, right;
      XawTextBlock block;
      Bool changed = False;
      unsigned char ch, mb[sizeof(wchar_t)];
      int i, count;
  
      if (mul > 0)
  	right = SrcScan(ctx->text.source, left = ctx->text.insertPos,
  			XawstAlphaNumeric, XawsdRight, mul, False);
      else
  	left = SrcScan(ctx->text.source, right = ctx->text.insertPos,
  		       XawstAlphaNumeric, XawsdLeft, 1 + -mul, False);
      block.firstPos = 0;
      block.format = _XawTextFormat(ctx);
      block.length = right - left;
      block.ptr = _XawTextGetText(ctx, left, right);
  
      count = 0;
      if (block.format == XawFmt8Bit)
  	for (i = 0; i < block.length; i++) {
  	    if (!IsAlnum(*mb = (unsigned char)block.ptr[i]))
  		count = 0;
  	    else if (++count == 1 || cmd != CAPITALIZE) {
  		ch = cmd == DOWNCASE ? ToLower(*mb) : ToUpper(*mb);
  		if (ch != *mb) {
  		    changed = True;
  		    block.ptr[i] = ch;
  		}
  	    }
  	    else if (cmd == CAPITALIZE) {
  		if ((ch = ToLower(*mb)) != *mb) {
  		    changed = True;
  		    block.ptr[i] = ch;
  		}
  	    }
  	}
      else
  	for (i = 0; i < block.length; i++) {
  	    wctomb((char*)mb, ((wchar_t*)block.ptr)[i]);
  	    if (!IsAlnum(*mb))
  		count = 0;
  	    else if (++count == 1 || cmd != CAPITALIZE) {
  		ch = cmd == DOWNCASE ? ToLower(*mb) : ToUpper(*mb);
  		if (ch != *mb) {
  		    changed = True;
  		    ((wchar_t*)block.ptr)[i] = _Xaw_atowc(ch);
  		}
  	    }
  	    else if (cmd == CAPITALIZE) {
  		if ((ch = ToLower(*mb)) != *mb) {
  		    changed = True;
  		    ((wchar_t*)block.ptr)[i] = _Xaw_atowc(ch);
  		}
  	    }
  	}
  
      StartAction(ctx, event);
      if (changed && _XawTextReplace(ctx, left, right, &block) != XawEditDone)
  	XBell(XtDisplay(ctx), 0);
      ctx->text.insertPos = right;
      EndAction(ctx);
  
      XtFree(block.ptr);
  }
  
  /*ARGSUSED*/
  static void
  CapitalizeWord(Widget w, XEvent *event, String *params, Cardinal *num_params)
  {
      CaseProc(w, event, CAPITALIZE);
  }
  
  /*ARGSUSED*/
  static void
  DowncaseWord(Widget w, XEvent *event, String *params, Cardinal *num_params)
  {
      CaseProc(w, event, DOWNCASE);
  }
  
  /*ARGSUSED*/
  static void
  UpcaseWord(Widget w, XEvent *event, String *params, Cardinal *num_params)
  {
      CaseProc(w, event, UPCASE);
  }
  #undef CAPITALIZE
  #undef DOWNCASE
  #undef UPCASE
  
  XtActionsRec _XawTextActionsTable[] = {
    /* motion */
    {"forward-character",		MoveForwardChar},
    {"backward-character",	MoveBackwardChar},
    {"forward-word",		MoveForwardWord},
    {"backward-word",		MoveBackwardWord},
    {"forward-paragraph",		MoveForwardParagraph},
    {"backward-paragraph",	MoveBackwardParagraph},
    {"beginning-of-line",		MoveToLineStart},
    {"end-of-line",		MoveToLineEnd},
    {"next-line",			MoveNextLine},
    {"previous-line",		MovePreviousLine},
    {"next-page",			MoveNextPage},
    {"previous-page",		MovePreviousPage},
    {"beginning-of-file",		MoveBeginningOfFile},
    {"end-of-file",		MoveEndOfFile},
    {"scroll-one-line-up",	ScrollOneLineUp},
    {"scroll-one-line-down",	ScrollOneLineDown},
  
    /* delete */
    {"delete-next-character",	DeleteForwardChar},
    {"delete-previous-character",	DeleteBackwardChar},
    {"delete-next-word",		DeleteForwardWord},
    {"delete-previous-word",	DeleteBackwardWord},
    {"delete-selection",		DeleteCurrentSelection},
    {"delete",			Delete},
  
    /* kill */
    {"kill-word",			KillForwardWord},
    {"backward-kill-word",	KillBackwardWord},
    {"kill-selection",		KillCurrentSelection},
    {"kill-to-end-of-line",	KillToEndOfLine},
    {"kill-to-end-of-paragraph",	KillToEndOfParagraph},
  
    /* new line */
    {"newline-and-indent",	InsertNewLineAndIndent},
    {"newline-and-backup",	InsertNewLineAndBackup},
    {"newline",			InsertNewLine},
  
    /* selection */
    {"select-word",		SelectWord},
    {"select-all",		SelectAll},
    {"select-start",		SelectStart},
    {"select-adjust",		SelectAdjust},
    {"select-end",		SelectEnd},
    {"select-save",		SelectSave},
    {"extend-start",		ExtendStart},
    {"extend-adjust",		ExtendAdjust},
    {"extend-end", 		ExtendEnd},
    {"insert-selection",		InsertSelection},
  
    /* miscellaneous */
    {"redraw-display",		RedrawDisplay},
    {"insert-file",		_XawTextInsertFile},
    {"search",			_XawTextSearch},
    {"insert-char",		InsertChar},
    {"insert-string",		InsertString},
    {"focus-in",			TextFocusIn},
    {"focus-out",			TextFocusOut},
    {"enter-window",		TextEnterWindow},
    {"leave-window",		TextLeaveWindow},
    {"display-caret",		DisplayCaret},
    {"multiply",			Multiply},
    {"form-paragraph",		FormParagraph},
    {"transpose-characters",	TransposeCharacters},
    {"set-keyboard-focus",	SetKeyboardFocus},
  #ifndef OLDXAW
    {"numeric",			Numeric},
    {"undo",			Undo},
    {"keyboard-reset",		KeyboardReset},
    {"kill-ring-yank",		KillRingYank},
    {"toggle-overwrite",		ToggleOverwrite},
    {"indent",			Indent},
  #endif
    {"no-op",			NoOp},
  
    /* case transformations */
    {"capitalize-word",		CapitalizeWord},
    {"downcase-word",		DowncaseWord},
    {"upcase-word",		UpcaseWord},
  
    /* action to bind translations for text dialogs */
    {"InsertFileAction",		_XawTextInsertFileAction},
    {"DoSearchAction",		_XawTextDoSearchAction},
    {"DoReplaceAction",		_XawTextDoReplaceAction},
    {"SetField",			_XawTextSetField},
    {"PopdownSearchAction",	_XawTextPopdownSearchAction},
  
    /* reconnect to Input Method */
    {"reconnect-im",		Reconnect} /* Li Yuhong, Omron KK, 1991 */
  };
  
  Cardinal _XawTextActionsTableCount = XtNumber(_XawTextActionsTable);
  