Edit

IABSD.fr/xenocara/lib/libXaw/src/TextAction.c

Branch :

  • Show log

    Commit

  • Author : matthieu
    Date : 2006-11-25 16:53:47
    Hash : 59f6d906
    Message : import from X.Org 7.2RC2

  • lib/libXaw/src/TextAction.c
  • /* $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;
        } else {
    	XTextProperty textprop;
    	char **list;
    	int count;
    
    	textprop.encoding = *type;
    	textprop.value = (unsigned char *)value;
    	textprop.nitems = strlen(value);
    	textprop.format = 8;
    
    	if (XmbTextPropertyToTextList(d, &textprop, &list, &count)
    	    !=	Success
    	    || count < 1) {
    	    XFreeStringList(list);
    
    	    /* 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 (XmbTextPropertyToTextList(d, &textprop, &list, &count)
    		!=  Success
    		|| count < 1)
    		return;
    	}
    
    	XFree(value);
    	value = (XPointer)list[0];
    
    	*length = strlen(list[0]);
    	XtFree((XtPointer)list);
    	text.format = XawFmt8Bit;
        }
        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)
    {
        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, XA_UTF8_STRING(XtDisplay(w)),
    			    _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) && *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);