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

static const char rcsid[] = "$Header: /cvsroot/hungry/lesstif/lib/Xm/TextIn.c,v 1.46 2000/01/09 22:21:21 hennessy Exp $";

#include <LTconfig.h>
#include <Xm/XmP.h>
#include <XmI/XmI.h>
#include <Xm/TextP.h>
#include <X11/Xfuncs.h>
#include <stdio.h>
#ifdef HAVE_STRING_H
#include <string.h>
#define ANSI_STRING
#else
#include <strings.h>
#endif
#include <stdlib.h>

#include <XmI/DebugUtil.h>

static void Activate(Widget w, XEvent *ev, String *params,
		     Cardinal *num_params);
static void MoveBackwardChar(Widget w, XEvent *ev, String *params,
			     Cardinal *num_params);
static void MoveBackwardParagraph(Widget w, XEvent *ev, String *params,
				  Cardinal *num_params);
static void MoveBackwardWord(Widget w, XEvent *ev, String *params,
			     Cardinal *num_params);
static void RingBell(Widget w, XEvent *ev, String *params,
		     Cardinal *num_params);
static void MoveBeginningOfFile(Widget w, XEvent *ev, String *params,
				Cardinal *num_params);
static void MoveToLineStart(Widget w, XEvent *ev, String *params,
			    Cardinal *num_params);
static void ClearSelection(Widget w, XEvent *ev, String *params,
			   Cardinal *num_params);
static void CopyClipboard(Widget w, XEvent *ev, String *params,
			  Cardinal *num_params);
static void CopyPrimary(Widget w, XEvent *ev, String *params,
			Cardinal *num_params);
static void ProcessCopy(Widget w, XEvent *ev, String *params,
			Cardinal *num_params);
static void CutClipboard(Widget w, XEvent *ev, String *params,
			 Cardinal *num_params);
static void CutPrimary(Widget w, XEvent *ev, String *params,
		       Cardinal *num_params);
static void DeleteForwardChar(Widget w, XEvent *ev, String *params,
			      Cardinal *num_params);
static void DeleteBackwardChar(Widget w, XEvent *ev, String *params,
			       Cardinal *num_params);
static void DeleteForwardWord(Widget w, XEvent *ev, String *params,
			      Cardinal *num_params);
static void DeleteBackwardWord(Widget w, XEvent *ev, String *params,
			       Cardinal *num_params);
static void DeleteCurrentSelection(Widget w, XEvent *ev, String *params,
				   Cardinal *num_params);
static void DeleteToEndOfLine(Widget w, XEvent *ev, String *params,
			      Cardinal *num_params);
static void DeleteToStartOfLine(Widget w, XEvent *ev, String *params,
				Cardinal *num_params);
static void DeselectAll(Widget w, XEvent *ev, String *params,
			Cardinal *num_params);
static void DoSelection(Widget w, XEvent *ev, String *params,
			Cardinal *num_params);
static void MoveEndOfFile(Widget w, XEvent *ev, String *params,
			  Cardinal *num_params);
static void MoveToLineEnd(Widget w, XEvent *ev, String *params,
			  Cardinal *num_params);
static void ExtendEnd(Widget w, XEvent *ev, String *params,
		      Cardinal *num_params);
static void StartExtendSelection(Widget w, XEvent *ev, String *params,
				 Cardinal *num_params);
static void FindWord(Widget w, XEvent *ev, String *params,
		     Cardinal *num_params);
static void MoveForwardChar(Widget w, XEvent *ev, String *params,
			    Cardinal *num_params);
static void MoveForwardParagraph(Widget w, XEvent *ev, String *params,
				 Cardinal *num_params);
static void MoveForwardWord(Widget w, XEvent *ev, String *params,
			    Cardinal *num_params);
static void DoGrabFocus(Widget w, XEvent *ev, String *params,
			Cardinal *num_params);
static void InsertString(Widget w, XEvent *ev, String *params,
			 Cardinal *num_params);
static void KeySelection(Widget w, XEvent *ev, String *params,
			 Cardinal *num_params);
static void KillForwardChar(Widget w, XEvent *ev, String *params,
			    Cardinal *num_params);
static void KillForwardWord(Widget w, XEvent *ev, String *params,
			    Cardinal *num_params);
static void KillBackwardChar(Widget w, XEvent *ev, String *params,
			     Cardinal *num_params);
static void KillBackwardWord(Widget w, XEvent *ev, String *params,
			     Cardinal *num_params);
static void KillCurrentSelection(Widget w, XEvent *ev, String *params,
				 Cardinal *num_params);
static void KillToEndOfLine(Widget w, XEvent *ev, String *params,
			    Cardinal *num_params);
static void KillToStartOfLine(Widget w, XEvent *ev, String *params,
			      Cardinal *num_params);
static void MoveDestination(Widget w, XEvent *ev, String *params,
			    Cardinal *num_params);
static void ProcessMove(Widget w, XEvent *ev, String *params,
			Cardinal *num_params);
static void InsertNewLine(Widget w, XEvent *ev, String *params,
			  Cardinal *num_params);
static void InsertNewLineAndBackup(Widget w, XEvent *ev, String *params,
				   Cardinal *num_params);
static void InsertNewLineAndIndent(Widget w, XEvent *ev, String *params,
				   Cardinal *num_params);
static void MoveNextLine(Widget aw, XEvent *ev, String *params,
			 Cardinal *num_params);
static void MoveNextPage(Widget aw, XEvent *ev, String *params,
			 Cardinal *num_params);
static void TraverseNextTabGroup(Widget w, XEvent *ev, String *params,
				 Cardinal *num_params);
static void MovePageLeft(Widget w, XEvent *ev, String *params,
			 Cardinal *num_params);
static void MovePageRight(Widget w, XEvent *ev, String *params,
			  Cardinal *num_params);
static void PasteClipboard(Widget w, XEvent *ev, String *params,
			   Cardinal *num_params);
static void TraversePrevTabGroup(Widget w, XEvent *ev, String *params,
				 Cardinal *num_params);
static void MovePreviousLine(Widget aw, XEvent *ev, String *params,
			     Cardinal *num_params);
static void MovePreviousPage(Widget aw, XEvent *ev, String *params,
			     Cardinal *num_params);
static void ProcessBDrag(Widget w, XEvent *ev, String *params,
			 Cardinal *num_params);
static void ProcessCancel(Widget w, XEvent *ev, String *params,
			  Cardinal *num_params);
static void ProcessDown(Widget w, XEvent *ev, String *params,
			Cardinal *num_params);
static void ProcessUp(Widget w, XEvent *ev, String *params,
		      Cardinal *num_params);
static void ProcessHome(Widget w, XEvent *ev, String *params,
			Cardinal *num_params);
static void ProcessReturn(Widget w, XEvent *ev, String *params,
			  Cardinal *num_params);
static void ProcessShiftDown(Widget w, XEvent *ev, String *params,
			     Cardinal *num_params);
static void ProcessShiftUp(Widget w, XEvent *ev, String *params,
			   Cardinal *num_params);
static void ProcessTab(Widget w, XEvent *ev, String *params,
		       Cardinal *num_params);
static void RedrawDisplay(Widget w, XEvent *ev, String *params,
			  Cardinal *num_params);
static void ScrollCursorVertically(Widget w, XEvent *ev, String *params,
			    Cardinal *num_params);
static void ScrollOneLineDown(Widget w, XEvent *ev, String *params,
			      Cardinal *num_params);
static void ScrollOneLineUp(Widget w, XEvent *ev, String *params,
			    Cardinal *num_params);
static void SecondaryAdjust(Widget w, XEvent *ev, String *params,
			    Cardinal *num_params);
static void SecondaryNotify(Widget w, XEvent *ev, String *params,
			    Cardinal *num_params);
static void SecondaryStart(Widget w, XEvent *ev, String *params,
			    Cardinal *num_params);
static void ExtendSelection(Widget w, XEvent *ev, String *params,
			    Cardinal *num_params);
static void SelectAll(Widget w, XEvent *ev, String *params,
		      Cardinal *num_params);
static void StartExtendSelection(Widget w, XEvent *ev, String *params,
				 Cardinal *num_params);
static void SelfInsert(Widget w, XEvent *ev, String *params,
		       Cardinal *num_params);
static void SetAnchor(Widget w, XEvent *ev, String *params,
		      Cardinal *num_params);
static void SetCursorPosition(Widget w, XEvent *ev, String *params,
			      Cardinal *num_params);
static void SetSelectionHint(Widget w, XEvent *ev, String *params,
			     Cardinal *num_params);
static void ToggleAddMode(Widget w, XEvent *ev, String *params,
			  Cardinal *num_params);
static void ToggleOverstrike(Widget w, XEvent *ev, String *params,
			  Cardinal *num_params);
static void TraverseHome(Widget w, XEvent *ev, String *params,
			 Cardinal *num_params);
static void TraverseDown(Widget w, XEvent *ev, String *params,
			 Cardinal *num_params);
static void TraverseUp(Widget w, XEvent *ev, String *params,
		       Cardinal *num_params);
static void TextFocusIn(Widget w, XEvent *ev, String *params,
			Cardinal *num_params);
static void TextFocusOut(Widget w, XEvent *ev, String *params,
			 Cardinal *num_params);
static void TextLeave(Widget w, XEvent *ev, String *params,
		      Cardinal *num_params);
static void VoidAction(Widget w, XEvent *ev, String *params,
		       Cardinal *num_params);
static void UnKill(Widget w, XEvent *ev, String *params,
		   Cardinal *num_params);

extern void LineTable(XmTextWidget w);

#define Offset(field) XtOffsetOf(XmTextInnerRec, inner.in.field)

/* Resources for the TextIn class */
static XtResource input_resources[] =
{
    {
	XmNpendingDelete, XmCPendingDelete, XmRBoolean,
	sizeof(Boolean), Offset(pendingdelete),
	XmRImmediate, (XtPointer)True
    },
    {
	XmNselectionArray, XmCSelectionArray, XmRPointer,
	sizeof(XtPointer), Offset(sarray),
	XmRImmediate, (XtPointer)NULL
	/* FIX ME: Motif has XmRInt, wacky value here */
    },
    {
	XmNselectionArrayCount, XmCSelectionArrayCount, XmRInt,
	sizeof(int), Offset(sarraycount),
	XmRImmediate, (XtPointer)3
	/* FIX ME: Motif has XmRInt, (XtPointer)whacko value here */
    },
    {
	XmNselectThreshold, XmCSelectThreshold, XmRInt,
	sizeof(int), Offset(threshold),
	XmRImmediate, (XtPointer)5
    },
};

/* action table table */

static XtActionsRec ZdefaultTextActionsTable[] =
{
    {"activate", Activate},
    {"backward-character", MoveBackwardChar},
    {"backward-paragraph", MoveBackwardParagraph},
    {"backward-word", MoveBackwardWord},
    {"beep", RingBell},
    {"beginning-of-file", MoveBeginningOfFile},
    {"beginning-of-line", MoveToLineStart},
    {"clear-selection", ClearSelection},
    {"copy-clipboard", CopyClipboard},
    {"copy-primary", CopyPrimary},
    {"copy-to", ProcessCopy},
    {"cut-clipboard", CutClipboard},
    {"cut-primary", CutPrimary},
    {"delete-next-character", DeleteForwardChar},
    {"delete-previous-character", DeleteBackwardChar},
    {"delete-next-word", DeleteForwardWord},
    {"delete-previous-word", DeleteBackwardWord},
    {"delete-selection", DeleteCurrentSelection},
    {"delete-to-end-of-line", DeleteToEndOfLine},
    {"delete-to-start-of-line", DeleteToStartOfLine},
    {"deselect-all", DeselectAll},
    {"do-quick-action", VoidAction},
    {"end-of-file", MoveEndOfFile},
    {"end-of-line", MoveToLineEnd},
    {"enter", _XmPrimitiveEnter},
    {"extend-adjust", ExtendSelection},
    {"extend-end", ExtendEnd},
    {"extend-start", StartExtendSelection},
    {"find-word", FindWord},
    {"forward-character", MoveForwardChar},
    {"forward-paragraph", MoveForwardParagraph},
    {"forward-word", MoveForwardWord},
    {"grab-focus", DoGrabFocus},
    {"Help", _XmPrimitiveHelp},
    {"insert-string", InsertString},
    {"key-select", KeySelection},
    {"kill-next-character", KillForwardChar},
    {"kill-next-word", KillForwardWord},
    {"kill-previous-character", KillBackwardChar},
    {"kill-previous-word", KillBackwardWord},
    {"kill-selection", KillCurrentSelection},
    {"kill-to-end-of-line", KillToEndOfLine},
    {"kill-to-start-of-line", KillToStartOfLine},
    {"leave", TextLeave},
    {"move-destination", MoveDestination},
    {"move-to", ProcessMove},
    {"newline", InsertNewLine},
    {"newline-and-backup", InsertNewLineAndBackup},
    {"newline-and-indent", InsertNewLineAndIndent},
    {"next-line", MoveNextLine},
    {"next-page", MoveNextPage},
    {"next-tab-group", TraverseNextTabGroup},
    {"page-left", MovePageLeft},
    {"page-right", MovePageRight},
    {"paste-clipboard", PasteClipboard},
    {"prev-tab-group", TraversePrevTabGroup},
    {"previous-line", MovePreviousLine},
    {"previous-page", MovePreviousPage},
    {"process-bdrag", ProcessBDrag},
    {"process-cancel", ProcessCancel},
    {"process-down", ProcessDown},
    {"process-up", ProcessUp},
    {"process-home", ProcessHome},
    {"process-return", ProcessReturn},
    {"process-shift-down", ProcessShiftDown},
    {"process-shift-up", ProcessShiftUp},
    {"process-tab", ProcessTab},
    {"quick-copy-set", VoidAction},
    {"quick-cut-set", VoidAction},
    {"redraw-display", RedrawDisplay},
    {"scroll-cursor-vertically", ScrollCursorVertically},
    {"scroll-one-line-down", ScrollOneLineDown},
    {"scroll-one-line-up", ScrollOneLineUp},
    {"secondary-adjust", SecondaryAdjust},
    {"secondary-notify", SecondaryNotify},
    {"secondary-start", SecondaryStart},
    {"select-adjust", DoSelection},
    {"select-all", SelectAll},
    {"select-end", DoSelection},
    {"select-start", StartExtendSelection},
    {"self-insert", SelfInsert},
    {"set-anchor", SetAnchor},
    {"set-insertion-point", SetCursorPosition},
    {"set-selection-hint", SetSelectionHint},
    {"toggle-add-mode", ToggleAddMode},
    {"toggle-overstrike", ToggleOverstrike},
    {"traverse-home", TraverseHome},
    {"traverse-next", TraverseDown},
    {"traverse-prev", TraverseUp},
    {"focusIn", TextFocusIn},
    {"focusOut", TextFocusOut},
    {"unkill", UnKill},
    {"unmap", _XmPrimitiveUnmap},
};


XtPointer _XmdefaultTextActionsTable = (XtPointer)ZdefaultTextActionsTable;

Cardinal _XmdefaultTextActionsTableSize = XtNumber(ZdefaultTextActionsTable);

static void
Invalidate(XmTextWidget w, XmTextPosition start, XmTextPosition end,
	   long delta)
{
    if ( delta == PASTENDPOS )
	In_HighlightEnd(Text_InputData(w)) = 0 ;
    else
	{
	/*CP:This works in some cases but not all !!
	In_HighlightEnd(Text_InputData(w)) += delta ;
	CP*/
	}
}

static void
InputGetValues(Widget w, ArgList args, Cardinal num_args)
{
    XtGetSubvalues(Text_InnerWidget(w),
		   input_resources, XtNumber(input_resources),
		   args, num_args);

    DEBUGOUT(XdbDebug(__FILE__, w, "InputGetValues :\n"));

    XdbPrintArgList(__FILE__, w, args, num_args, True);
}

/*
 * Something analogous to OutputSetValues should probably happen here.
 * This means we'll have to create a temporary copy of some stuff, something
 * that Xt normally does for us. Unfortunately, somebody (me - hehe) got the
 * unfortunate idea to implement things this way.
 * Other ways are probably more trouble...
 */
static void
InputSetValues(Widget old, Widget request, Widget new,
	       ArgList args, Cardinal *num_args)
{
    DEBUGOUT(XdbDebug(__FILE__, new, "InputSetValues :\n"));

    DEBUGOUT(XdbPrintArgList(__FILE__, new, args, *num_args, False));

/* FIX ME : Need to treat the following resources :
 *    XmNpendingDelete
 *      XmNselectionArray + XmNselectionArrayCount
 *      XmNselectThreshold
 */
}

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

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

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

    XtFree((XtPointer)In_SelArray(Text_Input(w)->data) );
    XtFree((char *)Text_Input(w));
}

static void
GetSecResData(XmSecondaryResourceData *secres)
{
}

InputRec inputRec =
{
    /* _InputDataRec             */ NULL,
    /* InputInvalidateProc       */ Invalidate,
    /* InputGetValuesProc        */ InputGetValues,
    /* InputSetValuesProc        */ InputSetValues,
    /* XtWidgetProc              */ InputDestroy,
    /* InputGetSecResProc        */ GetSecResData
};

void
_XmTextInputCreate(Widget aw, ArgList args, Cardinal num_args)
{
    XmTextWidget w = (XmTextWidget)aw;
    XmTextInnerWidget iw = (XmTextInnerWidget)w->text.inner_widget;
    InputData i;

    Text_Input(w) = (Input)XtMalloc(sizeof(InputRec));
    bcopy(&inputRec, Text_Input(w), sizeof(InputRec));

    i = Text_Input(w)->data = &iw->inner.in;

    XtGetSubresources(aw, iw,
		      aw->core.name,
		      aw->core.widget_class->core_class.class_name,
		      input_resources,
		      XtNumber(input_resources),
		      args, num_args);


    if (!Text_Source(w))
    {
	Text_Source(w) = _XmStringSourceCreate(Text_Value(w), False);
	Text_Source(w) -> data -> editable = Text_Editable(w);
    }

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

      /* CP :Thursday 13 May 1999
	FIXME : is this correct for version 2.x ? */
    In_SelArray(i) = (XmTextScanType*)XtMalloc ( sizeof(XmTextScanType) * 4 );
    In_SelArray(i)[0] = XmSELECT_POSITION;
    In_SelArray(i)[1] = XmSELECT_WORD;
    In_SelArray(i)[2] = XmSELECT_LINE;
    In_SelArray(i)[3] = XmSELECT_ALL;
    In_SelArrayCount(i) = 4;
    In_SelArrayIndex(i) = 0;

    In_LastTime(i) = 0;
    In_HighlightStart(i) = 0;
    i->extendDir = XmsdRight;
    i->cancel = True;

    DEBUGOUT(XdbDebug(__FILE__, aw,
		      "_XmTextInputCreate (selectionArrayCount %d)\n",
		      In_SelArrayCount(i)));

    DEBUGOUT(XdbPrintArgList(__FILE__, aw, args, num_args, False));
}


/* Scan type utilities ---------------------------------------------------
 */
static XmTextScanType
ScanType(XmTextWidget w)
{
    InputData i = Text_InputData(w);
    XmTextScanType type;

    if (In_SelArray(i))
    {
	if (In_SelArrayIndex(i) >= In_SelArrayCount(i))
	{
	    In_SelArrayIndex(i) = 0;
	}

	type = In_SelArray(i)[In_SelArrayIndex(i)];
    }
    else
    {
	switch (In_SelArrayIndex(i))
	{
	case 1:
	    type = XmSELECT_WORD;
	    break;

	case 2:
	    type = XmSELECT_LINE;
	    break;

	case 3:
	    type = XmSELECT_ALL;
	    break;

	default:
	    type = XmSELECT_POSITION;
	    In_SelArrayIndex(i) = 0;
	    break;
	}
    }

    DEBUGOUT(XdbDebug(__FILE__, (Widget)w,
		      "ScanType(%d) -> %s\n", In_SelArray(i),
		      (type == XmSELECT_WORD) ? "XmSELECT_WORD" :
		      (type == XmSELECT_LINE) ? "XmSELECT_LINE" :
		      (type == XmSELECT_ALL) ? "XmSELECT_ALL" :
		   (type == XmSELECT_POSITION) ? "XmSELECT_POSITION" : "???"));

    return type;
}



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

static void
VerifyBell(XmTextWidget w)
{
    if (Text_VerifyBell(w))
    {
	XBell(XtDisplay((Widget)w), 50);
    }
}

#if 0
static Boolean
DoCursorMove(XmTextWidget w, XEvent *ev, XmTextPosition pos)
{
    Widget aw = (Widget)w;

    if (pos > Text_LastPos(w))
	pos = Text_LastPos(w);

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

	XtCallCallbacks(aw, XmNmotionVerifyCallback, &cbs);

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

    if (cbs.doit)
    {
	_XmTextSetCursorPosition(aw, pos);
    }
    else
    {
	VerifyBell(w);
    }
    return cbs.doit;
}
#endif

/* Need this in XmTextRemove, hence no longer static */
void
_XmTextDelete(XmTextWidget w, XEvent *ev, XmTextPosition start, XmTextPosition end)
{
    Widget aw = (Widget)w;
    XmTextVerifyCallbackStruct cbs;
    XmTextBlockRec blockrec;

    if (end <= 0)
    {
	end = 0;
    }

    blockrec.ptr = NULL;
    blockrec.length = 0;
    blockrec.format = XmFMT_8_BIT;

    cbs.reason = XmCR_MODIFYING_TEXT_VALUE;
    cbs.event = ev;
    cbs.startPos = cbs.newInsert = start;
    cbs.endPos = end;
    cbs.currInsert = Text_CursorPos(w);
    cbs.text = &blockrec;
    cbs.doit = True;

    if (Text_ModifyVerifyCallback(w))
    {
	XtCallCallbacks((Widget)w, XmNmodifyVerifyCallback, &cbs);

	if (!cbs.doit)
	{
	    VerifyBell(w);
	}
    }

    if (cbs.doit)
    {
	XmTextStatus status;

	start = cbs.startPos;
	end = cbs.endPos;
	status = (*Text_Source(w)->Replace) (w, ev, &start, &end,
					     &blockrec, True);

	if (status == EditDone)
	{
	    /*
	     * FIX ME - This code probably belongs in TextStrSo.c.
	     * Think about what should happen if multiple widgets use one
	     * source.
	     * Danny 8/5/1997
	     */
/*CP:17 May 1999: this does not seem to be needed
	    _XmTextUpdateLineTable((Widget)w, cbs.startPos,
				   cbs.endPos, &blockrec, True);
*/
	    _XmTextSetCursorPosition(aw, cbs.newInsert);
	}
    }

    /* FIX ME:  Are we required to free this if it exists?  It can only exist
     * if the user made it, but does Motif think that the user malloced it?
     */
/*   if (blockrec.ptr) XtFree(blockrec.ptr); */
}

static void
DoInsert(XmTextWidget w, XEvent *ev, char *buf, int len)
{
    Widget aw = (Widget)w;
    XmTextVerifyCallbackStruct cbs;
    XmTextBlockRec blockrec;
    Boolean sel;
    XmTextPosition left, right;

    if (len <= 0)
    {
	return;
    }

    if (!Text_Editable(w))
    {
	VerifyBell(w);
	return;
    }

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

    blockrec.ptr = XtMalloc(len + 1);
    blockrec.length = len;
    blockrec.format = XmFMT_8_BIT;
    strncpy(blockrec.ptr, buf, len);
    blockrec.ptr[len] = '\0';

    /* Danny 1/7/97 */
    if (Text_CursorPos(w) == PASTENDPOS)
    {
	Text_CursorPos(w) = Text_LastPos(w);	/* End of text */
    }

    cbs.reason = XmCR_MODIFYING_TEXT_VALUE;
    cbs.event = ev;

    /* SG 23/08/1998, replace primary selection if exists, pending delete
       is true and the insertion cursor is inside the selection.
     */
    sel = (*Text_Source(w)->GetSelection) (Text_Source(w), &left, &right);

    if (sel && In_PendingDelete(Text_Input(w)->data) &&
        Text_CursorPos(w)>=left && Text_CursorPos(w)<=right)
    {
        cbs.currInsert = Text_CursorPos(w);
        cbs.startPos = left;
        cbs.endPos = right;
        cbs.newInsert = left + blockrec.length;
    }
    else
    {
        cbs.currInsert = cbs.startPos = cbs.endPos = Text_CursorPos(w);
        cbs.newInsert = cbs.currInsert + blockrec.length;
    }

    DEBUGOUT(XdbDebug(__FILE__, (Widget)w,
		      "DoInsert before CB: CursorPos %08x len %08x\n",
		      Text_CursorPos(w), len));

    cbs.text = &blockrec;
    cbs.doit = True;

    if (Text_ModifyVerifyCallback(w))
    {
	XtCallCallbacks((Widget)w, XmNmodifyVerifyCallback, &cbs);

	if (!cbs.doit)
	{
	    VerifyBell(w);
	}
    }

    if (cbs.doit)
    {
	XmTextStatus status;
	XmTextPosition start, end;

	start = cbs.startPos;
	end = cbs.endPos;
	DEBUGOUT(XdbDebug(__FILE__, (Widget)w,
			  "DoInsert: start %08x:%08x end %08x:%08x\n",
			  start, cbs.startPos, end, cbs.endPos));
	status = (*Text_Source(w)->Replace) (w, ev, &start,
					     &end, &blockrec, True);

	if (status == EditDone)
	{
	    _XmTextSetCursorPosition(aw, cbs.newInsert);
	}
    }

    XtFree(blockrec.ptr);
}

/*
 * Figure out what is supposed to get selected after this many clicks,
 *      also select it.
 * Number of clicks was recorded elsewhere, and stored into
 *      In_SelArrayIndex(Text_InputData(w)). The function ScanType()
 *      translates that into a type of selection (e.g. XmSELECT_WORD),
 *      based on which we really select text here.
 */
static void
DoScanType(XmTextWidget w, XEvent *ev, XmTextPosition pos)
{
    InputData i = Text_InputData(w);
    XmTextScanType st = ScanType(w);
    XmTextPosition left, right;

    switch (st)
    {
    case XmSELECT_POSITION:
	DEBUGOUT(XdbDebug(__FILE__, (Widget)w,
			  "DoScanType: XmSELECT_POSITION\n"));

	_XmTextSetCursorPosition((Widget)w, pos);

	/* Undo selection */
	XmTextSetSelection((Widget)w, pos, pos, ev->xbutton.time);

	In_HighlightPivot(i) = Text_CursorPos(w);
	break;

    case XmSELECT_WORD:
	right = (*Text_Source(w)->Scan) (Text_Source(w), pos, st,
					 XmsdRight, 1, False);
	left = (*Text_Source(w)->Scan) (Text_Source(w), right, st,
					XmsdLeft, 1, False);
        In_HighlightPivot(i) = left;

	DEBUGOUT(XdbDebug(__FILE__, (Widget)w,
		       "DoScanType: XmSELECT_WORD (left %d pos %d right %d)\n",
			  left, pos, right));

	XmTextSetSelection((Widget)w, left, right, ev->xbutton.time);

	break;

    case XmSELECT_LINE:
	right = (*Text_Source(w)->Scan) (Text_Source(w), pos, st,
					 XmsdRight, 1, False);
	left = (*Text_Source(w)->Scan) (Text_Source(w), right, st,
					XmsdLeft, 1, False);
        In_HighlightPivot(i) = left;

	DEBUGOUT(XdbDebug(__FILE__, (Widget)w,
		       "DoScanType: XmSELECT_LINE (left %d pos %d right %d)\n",
			  left, pos, right));

	XmTextSetSelection((Widget)w, left, right + 1, ev->xbutton.time);
	break;

#if	XmVERSION > 1
    case XmSELECT_OUT_LINE:	/* Motif 2.* feature - unimplemented here */
	DEBUGOUT(XdbDebug(__FILE__, (Widget)w,
			  "DoScanType: XmSELECT_OUT_LINE\n"));
	break;
#endif

    case XmSELECT_ALL:
	In_HighlightPivot(i) = left = 0;
	right = XmTextGetLastPosition((Widget)w);

	DEBUGOUT(XdbDebug(__FILE__, (Widget)w,
			"DoScanType: XmSELECT_ALL (left %d pos %d right %d)\n",
			  left, pos, right));

	XmTextSetSelection((Widget)w, left, right, ev->xbutton.time);

	break;

    default:
	DEBUGOUT(XdbDebug(__FILE__, (Widget)w, "DoScanType: ???\n"));

	break;
    }
}



/* Action Routines -------------------------------------------------------- */

static void
Activate(Widget w, XEvent *ev, String *params, Cardinal *num_params)
{
    XmTextWidget tw = (XmTextWidget)w;
    XmAnyCallbackStruct cb;

    if (Text_EditMode(tw) != XmSINGLE_LINE_EDIT)
    {
	return;
    }

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

    cb.reason = XmCR_ACTIVATE;
    cb.event = ev;

    XtCallCallbackList(w, tw->text.activate_callback, (XtPointer)&cb);
    if (XmIsManager(XtParent(w)))
    {
        XmParentProcessDataRec data;

	data.input_action.process_type = XmINPUT_ACTION;
	data.input_action.event = ev;
	data.input_action.action = XmPARENT_ACTIVATE;
	data.input_action.params = params;
	data.input_action.num_params = num_params;

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

static void
MoveBackwardChar(Widget w, XEvent *ev, String *params, Cardinal *num_params)
{
    DEBUGOUT(XdbDebug(__FILE__, w, "MoveBackwardChar\n"));

    if (Text_CursorPos(w) > 0)
    {
	(*Text_Output(w)->DrawInsertionPoint) ((XmTextWidget)w,
					       Text_CursorPos(w), off);
	_XmTextSetCursorPosition((Widget)w, Text_CursorPos(w) - 1);
    }
}

static void
MoveBackwardParagraph(Widget w, XEvent *ev,
		      String *params, Cardinal *num_params)
{
    DEBUGOUT(XdbDebug(__FILE__, w, "MoveBackwardParagraph"));

    if (Text_CursorPos(w) > 0)
    {
	XmTextPosition pos;

	pos = (*Text_Source(w)->Scan) (Text_Source(w), Text_CursorPos(w),
				     XmSELECT_WHITESPACE, XmsdLeft, 1, False);

	pos = (*Text_Source(w)->Scan) (Text_Source(w), pos,
				       XmSELECT_PARAGRAPH, XmsdLeft, 1, False);

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

	_XmTextSetCursorPosition((Widget)w, pos);
    }
}

static void
MoveBackwardWord(Widget w, XEvent *ev, String *params, Cardinal *num_params)
{
    DEBUGOUT(XdbDebug(__FILE__, w, "MoweBackwardWord"));

    if (Text_CursorPos(w) > 0)
    {
	XmTextPosition pos;

	pos = (*Text_Source(w)->Scan) (Text_Source(w), Text_CursorPos(w),
				     XmSELECT_WHITESPACE, XmsdLeft, 1, False);

	pos = (*Text_Source(w)->Scan) (Text_Source(w), pos,
				       XmSELECT_WORD, XmsdLeft, 1, False);

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

	_XmTextSetCursorPosition((Widget)w, pos);
    }
}

static void
RingBell(Widget w, XEvent *ev, String *params, Cardinal *num_params)
{
    XBell(XtDisplay((Widget)w), 50);
}

static void
MoveBeginningOfFile(Widget w, XEvent *ev, String *params,
		    Cardinal *num_params)
{
    DEBUGOUT(XdbDebug(__FILE__, w, "MoveBeginningOfFile"));

    if (Text_CursorPos(w) > 0)
    {
	(*Text_Output(w)->DrawInsertionPoint) ((XmTextWidget)w,
					       Text_CursorPos(w), off);
	_XmTextSetCursorPosition(w, 0);
    }
}

static void
MoveToLineStart(Widget w, XEvent *ev, String *params,
		Cardinal *num_params)
{
    XmTextPosition pos;

    DEBUGOUT(XdbDebug(__FILE__, w, "MoveToLineStart"));

    pos = (*Text_Source(w)->Scan) (Text_Source(w), Text_CursorPos(w),
				   XmSELECT_LINE, XmsdLeft, 1, False);

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

    _XmTextSetCursorPosition(w, pos);
}

static void
ClearSelection(Widget w, XEvent *ev, String *params, Cardinal *num_params)
{
    DEBUGOUT(XdbDebug(__FILE__, w, "ClearSelection\n"));
}

static void
CopyClipboard(Widget w, XEvent *ev, String *params, Cardinal *num_params)
{
    DEBUGOUT(XdbDebug(__FILE__, w, "CopyClipboard\n"));
    XmTextCopy(w, ev->xkey.time);
}

static void
CopyPrimary(Widget w, XEvent *ev, String *params, Cardinal *num_params)
{
    DEBUGOUT(XdbDebug(__FILE__, w, "CopyPrimary\n"));
}

/*
 * _XmTextGetSelection is the function that's called when we receive the
 * string from a copy/paste operation.
 * Now we need to insert this text into our widget.
 *
 * It seems that if the widget is read only then we never get here
 * so there is no need to check this (SG 18/08/1998)
 */
static void
_XmTextGetSelection(Widget w, XtPointer client, Atom *selection, Atom *type,
		    XtPointer value, unsigned long *len, int *format)
{
    XEvent *ev = (XEvent *)client;

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

    if ((!value) || (*len == 0))
    {
    	if (*selection == XA_SECONDARY)
    	{
	    XtGetSelectionValue(w, XA_PRIMARY, XA_STRING, _XmTextGetSelection,
			(XtPointer)ev, ev->xbutton.time);
    	}
    	else
    	{
	    XtFree(client);
    	}
    }
    else
    {
	if (*type == XA_STRING)
	{
	    char *s = (char *)value;

	    if (s)
	    {
		if (*selection == XA_SECONDARY)
		{
		    DoInsert((XmTextWidget)w, ev, s, *len);
		}
		else
		{
		XmTextPosition pos;

		    pos = (*Text_Output(w)->XYToPos)((XmTextWidget)w,
		    			ev->xbutton.x, ev->xbutton.y);
		    XmTextSetCursorPosition(w, pos);
		    DoInsert((XmTextWidget)w, ev, s, *len);
		}
	    }
	}
	XtFree(value);
	XtFree(client);
    }
}

static void
ProcessCopy(Widget w, XEvent *ev, String *params, Cardinal *num_params)
{
    DEBUGOUT(XdbDebug(__FILE__, w, "ProcessCopy\n"));

    if (Text_Editable(w))
    {
    XEvent *nev;

    	nev = XtNew(XEvent);
    	*nev = *ev;
	XtGetSelectionValue(w, XA_SECONDARY, XA_STRING, _XmTextGetSelection,
			(XtPointer)nev, ev->xbutton.time);
    }
}

static void
ProcessCancel(Widget w, XEvent *ev, String *params, Cardinal *num_params)
{
    DEBUGOUT(XdbDebug(__FILE__, w, "ProcessCancel\n"));
}

static void
CutClipboard(Widget w, XEvent *ev, String *params, Cardinal *num_params)
{
    DEBUGOUT(XdbDebug(__FILE__, w, "CutClipboard\n"));
    XmTextCut(w, ev->xbutton.time);
}

static void
CutPrimary(Widget w, XEvent *ev, String *params, Cardinal *num_params)
{
    DEBUGOUT(XdbDebug(__FILE__, w, "CutPrimary\n"));
}

/*
 * The specs say :
 *    In normal (not add-mode) mode :
 *      - if there is a selection, delete it
 *      - else delete the next character.
 *    In add mode :
 *      - if there's a selection, and the cursor's in it,
 *        and PendingDelete is True, then delete the selection
 *      - otherwise delete the next character.
 */
static void
DeleteForwardChar(Widget w, XEvent *ev, String *params,
		  Cardinal *num_params)
{
    Boolean sel;
    XmTextPosition left, right;

    DEBUGOUT(XdbDebug(__FILE__, w, "DeleteForwardChar"));

    if (!Text_Editable(w))
    {
	VerifyBell((XmTextWidget)w);
	return;
    }

    sel = (*Text_Source(w)->GetSelection) (Text_Source(w), &left, &right);

    /* SG 22/08/1998 - O'Reilly, and experience says that Motif 1.2 deletes
       the selection as per the "add mode" sction above. However add mode
       is not mentioned at all as far as I can tell in Motif 1.2, is this
       a Motif 2.0 thing ? If so it doesn't belong here, except possibly
       ifdef'ed .
     */
    if (sel && In_PendingDelete(Text_Input(w)->data) &&
        Text_CursorPos(w)>=left && Text_CursorPos(w)<=right)
    {
        _XmTextDelete((XmTextWidget)w, ev, left, right);
    }
    else if (Text_CursorPos(w) < Text_LastPos(w))
    {
        _XmTextDelete((XmTextWidget)w, ev, Text_CursorPos(w),
    	     Text_CursorPos(w) + 1);
    }
}

static void
DeleteBackwardChar(Widget w, XEvent *ev, String *params,
		   Cardinal *num_params)
{
    Boolean sel;
    XmTextPosition left, right;
    DEBUGOUT(XdbDebug(__FILE__, w, "DeleteBackardChar"));

    if (!Text_Editable(w))
    {
	VerifyBell((XmTextWidget)w);
	return;
    }

    sel = (*Text_Source(w)->GetSelection) (Text_Source(w), &left, &right);

    if(sel && In_PendingDelete(Text_Input(w)->data) &&
       Text_CursorPos(w)>=left && Text_CursorPos(w)<=right)
    {
      _XmTextDelete((XmTextWidget)w,ev,left,right);
    }
    else if (Text_CursorPos(w) > 0)
    {
	_XmTextDelete((XmTextWidget)w, ev, Text_CursorPos(w) - 1, Text_CursorPos(w));
    }
}

static void
DeleteForwardWord(Widget w, XEvent *ev, String *params, Cardinal *num_params)
{
    Boolean sel;
    XmTextPosition left, right;
    DEBUGOUT(XdbDebug(__FILE__, w, "DeleteForwardWord\n"));

    if (!Text_Editable(w))
    {
	VerifyBell((XmTextWidget)w);
	return;
    }

    sel = (*Text_Source(w)->GetSelection) (Text_Source(w), &left, &right);

    if(sel && In_PendingDelete(Text_Input(w)->data) &&
       Text_CursorPos(w)>=left && Text_CursorPos(w)<=right)
    {
      _XmTextDelete((XmTextWidget)w,ev,left,right);
    }
    else
    {
    XmTextPosition pos;

        pos = (*Text_Source(w)->Scan) (Text_Source(w), Text_CursorPos(w),
                                       XmSELECT_WORD, XmsdRight, 1, False);

        pos = (*Text_Source(w)->Scan) (Text_Source(w), pos,
                                       XmSELECT_WHITESPACE, XmsdRight, 1, False);
        _XmTextDelete((XmTextWidget)w, ev,Text_CursorPos(w),pos);
    }
}

static void
DeleteBackwardWord(Widget w, XEvent *ev, String *params, Cardinal *num_params)
{
    Boolean sel;
    XmTextPosition left, right;
    DEBUGOUT(XdbDebug(__FILE__, w, "DeleteBackwardWord\n"));

    if (!Text_Editable(w))
    {
	VerifyBell((XmTextWidget)w);
	return;
    }

    sel = (*Text_Source(w)->GetSelection) (Text_Source(w), &left, &right);

    if(sel && In_PendingDelete(Text_Input(w)->data) &&
       Text_CursorPos(w)>=left && Text_CursorPos(w)<=right)
    {
      _XmTextDelete((XmTextWidget)w,ev,left,right);
    }
    else if (Text_CursorPos(w) > 0)
    {
        XmTextPosition pos;

        pos = (*Text_Source(w)->Scan) (Text_Source(w), Text_CursorPos(w),
                                     XmSELECT_WHITESPACE, XmsdLeft, 1, False);

        pos = (*Text_Source(w)->Scan) (Text_Source(w), pos,
                                       XmSELECT_WORD, XmsdLeft, 1, False);

        _XmTextDelete((XmTextWidget)w,ev,pos,Text_CursorPos(w));
    }
}

static void
DeleteCurrentSelection(Widget w, XEvent *ev,
		       String *params, Cardinal *num_params)
{
    Boolean sel;
    XmTextPosition left, right;

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

    if (!Text_Editable(w))
    {
        VerifyBell((XmTextWidget)w);
        return;
    }

    sel = (*Text_Source(w)->GetSelection) (Text_Source(w), &left, &right);

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

static void
DeleteToEndOfLine(Widget w, XEvent *ev, String *params, Cardinal *num_params)
{
    XmTextPosition pos;
    DEBUGOUT(XdbDebug(__FILE__, w, "DeleteToEndOfLine\n"));

    if (!Text_Editable(w))
    {
	VerifyBell((XmTextWidget)w);
	return;
    }

    pos = (*Text_Source(w)->Scan) (Text_Source(w), Text_CursorPos(w),
				   XmSELECT_LINE, XmsdRight, 1, False);
    _XmTextDelete((XmTextWidget)w,ev,Text_CursorPos(w),pos);
}

static void
DeleteToStartOfLine(Widget w, XEvent *ev, String *params, Cardinal *num_params)
{
    XmTextPosition pos;
    DEBUGOUT(XdbDebug(__FILE__, w, "DeleteToStartOfLine\n"));

    if (!Text_Editable(w))
    {
	VerifyBell((XmTextWidget)w);
	return;
    }

    pos = (*Text_Source(w)->Scan) (Text_Source(w), Text_CursorPos(w),
				   XmSELECT_LINE, XmsdLeft, 1, False);
    _XmTextDelete((XmTextWidget)w,ev,pos,Text_CursorPos(w));
}

static void
DeselectAll(Widget w, XEvent *ev, String *params, Cardinal *num_params)
{
    DEBUGOUT(XdbDebug(__FILE__, w, "DeselectAll\n"));
    (*Text_Source(w)->SetSelection)(Text_Source(w),-1,-1,ev->xkey.time);
}


static void
MoveToLineEnd(Widget w, XEvent *ev, String *params, Cardinal *num_params)
{
    XmTextPosition pos;

    DEBUGOUT(XdbDebug(__FILE__, w, "MoveToLineEnd"));

    pos = (*Text_Source(w)->Scan) (Text_Source(w), Text_CursorPos(w),
				   XmSELECT_LINE, XmsdRight, 1, False);
    (*Text_Output(w)->DrawInsertionPoint) ((XmTextWidget)w,
					   Text_CursorPos(w), off);
    _XmTextSetCursorPosition(w, pos);
}

static void
MoveEndOfFile(Widget w, XEvent *ev, String *params, Cardinal *num_params)
{
    XmTextPosition pos;

    DEBUGOUT(XdbDebug(__FILE__, w, "MoveToEndOfFile"));

    pos = Text_LastPos(w);

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

    _XmTextSetCursorPosition(w, pos);
}


static void
DoSelection(Widget w, XEvent *ev, String *params, Cardinal *num_params)
{
    if (ev->type != MotionNotify)
    {
	return;
    }

    DEBUGOUT(XdbDebug(__FILE__, w, "DoSelection"));
}

/*
 * ExtendEnd gets called at the end of a selection, e.g. after you've moved
 * the pointer while holding down MB1 (i.e. the left mouse button).
 * If, after that, MB1 is released, then this method is called.
 */
static void
ExtendEnd(Widget w, XEvent *ev, String *params, Cardinal *num_params)
{
    InputData i = Text_InputData(w);

    if (!i->extending)
    {
	return;
    }

    DEBUGOUT(XdbDebug(__FILE__, w, "ExtendEnd"));

    /*
     * Set a flag for ExtendSelection() to know that when it happens,
     * it must be a new selection.
     */
    i->extending = False;
}

/*
 * To continue the example above (comments above ExtendEnd), ExtendSelection
 * is called while moving the pointer while holding down MB1.
 */
static void
ExtendSelection(Widget w, XEvent *ev, String *params, Cardinal *num_params)
{
    XmTextPosition pos, left, right;
    XmTextScanType st;
    InputData i = Text_InputData(w);
    Boolean sel;

    pos = (*Text_Output(w)->XYToPos) ((XmTextWidget)w,
				      ev->xbutton.x, ev->xbutton.y);

    sel = (*Text_Source(w)->GetSelection) (Text_Source(w), &left, &right);

    if (sel)
    {
	DEBUGOUT(XdbDebug(__FILE__, w,
		 "ExtendSelection (pos %d, origleft %d) existing sel. %d-%d\n",
			  pos, In_HighlightPivot(i), left, right));
    }
    else
    {
	DEBUGOUT(XdbDebug(__FILE__, w,
	    "ExtendSelection (pos %d, origleft %d) (x %d y %d)\n",
	    pos, In_HighlightPivot(i), ev->xbutton.x, ev->xbutton.y));
    }

    if (In_HighlightPivot(i) < 0)
    {
	In_HighlightPivot(i) = pos;
    }

    st = ScanType((XmTextWidget)w);

    if(pos >= In_HighlightPivot(i))
    {
        if(st == XmSELECT_POSITION)
        {
            left = In_HighlightPivot(i);
            right = pos;
        }
        else
        {
            right = (*Text_Source(w)->Scan)(Text_Source(w), pos, st,
                                            XmsdRight, 1, False);
            left = In_HighlightPivot(i);
        }
        XmTextSetCursorPosition(w,right);
    }
    else
    {
        if(st == XmSELECT_POSITION)
        {
            left = pos;
            right = In_HighlightPivot(i);
        }
        else
        {
            left = (*Text_Source(w)->Scan)(Text_Source(w), pos, st,
                                           XmsdLeft, 1, False);
            right = (*Text_Source(w)->Scan)(Text_Source(w),In_HighlightPivot(i),
                                            st, XmsdRight, 1, False);
        }
        XmTextSetCursorPosition(w,left);
    }

    XmTextSetSelection(w,left,right,ev->xbutton.time);

    i->extending = True;
}

static void
FindWord(Widget w, XEvent *ev, String *params, Cardinal *num_params)
{
}

static void
MoveForwardChar(Widget w, XEvent *ev, String *params, Cardinal *num_params)
{
    DEBUGOUT(XdbDebug(__FILE__, w, "MoveForwardChar\n"));

    if (Text_CursorPos(w) < Text_LastPos(w))
    {
	(*Text_Output(w)->DrawInsertionPoint) ((XmTextWidget)w,
					       Text_CursorPos(w), off);
        _XmTextSetCursorPosition(w, Text_CursorPos(w) + 1);
    }
}

static void
MoveForwardParagraph(Widget w, XEvent *ev, String *params,
		     Cardinal *num_params)
{
    XmTextPosition pos;

    DEBUGOUT(XdbDebug(__FILE__, w, "MoveForwardParagraph"));

    pos = (*Text_Source(w)->Scan) (Text_Source(w), Text_CursorPos(w),
				   XmSELECT_PARAGRAPH, XmsdRight, 1, False);

    pos = (*Text_Source(w)->Scan) (Text_Source(w), pos,
				   XmSELECT_WHITESPACE, XmsdRight, 1, False);

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

    _XmTextSetCursorPosition(w, pos);
}


static void
MoveForwardWord(Widget w, XEvent *ev, String *params,
		Cardinal *num_params)
{
    XmTextPosition pos;

    DEBUGOUT(XdbDebug(__FILE__, w, "MoveForwardWord"));

    pos = (*Text_Source(w)->Scan) (Text_Source(w), Text_CursorPos(w),
				   XmSELECT_WORD, XmsdRight, 1, False);

    pos = (*Text_Source(w)->Scan) (Text_Source(w), pos,
				   XmSELECT_WHITESPACE, XmsdRight, 1, False);

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

    _XmTextSetCursorPosition(w, pos);
}

static void
DoGrabFocus(Widget w, XEvent *ev, String *params, Cardinal *num_params)
{
    InputData i = Text_InputData(w);
    XmTextPosition pos;

    DEBUGOUT(XdbDebug(__FILE__, w, "DoGrabFocus"));

    XmProcessTraversal((Widget)w, XmTRAVERSE_CURRENT);

    pos = (*Text_Output(w)->XYToPos) ((XmTextWidget)w,
				      ev->xbutton.x, ev->xbutton.y);

    if ((In_LastTime(i) + XtGetMultiClickTime(XtDisplay((Widget)w))) >
	ev->xbutton.time)
    {
	In_SelArrayIndex(i)++;
    }
    else
    {
	In_SelArrayIndex(i) = 0;
    }

    DoScanType((XmTextWidget)w, ev, pos);

    In_LastTime(i) = ev->xbutton.time;
}


static void
InsertString(Widget w, XEvent *ev, String *params, Cardinal *num_params)
{
    DEBUGOUT(XdbDebug(__FILE__, w, "InsertString\n"));
    if ( *num_params == 1 )
           XmTextInsert ( w, XmTextGetCursorPosition(w), params[0] );
}

static void
_KeySelection(Widget w, XEvent *ev, int flag, String *params, Cardinal *np)
{
    Boolean sel;
    XmTextPosition left, right, old;

    sel = (*Text_Source(w)->GetSelection) (Text_Source(w), &left, &right);

    switch (flag)
    {
    case 1:			/* left */
	old = Text_CursorPos(w);
	MoveBackwardChar(w, ev, params, np);

	DEBUGOUT(XdbDebug(__FILE__, w,
			  "KeySelection old %d new %d left %d right %d\n",
			  old, Text_CursorPos(w), left, right));

	if (old == Text_CursorPos(w))
	{
	    break;
	}

	if (sel)
	{			/* Already have a selection, extend it */
	    if (old == left)
	    {
		left = Text_CursorPos(w);
	    }

	    if (old == right)
	    {
		right = Text_CursorPos(w);
	    }
	}
	else
	{			/* New selection */
	    left = Text_CursorPos(w);
	    right = old;
	}

	(*Text_Source(w)->SetSelection) (Text_Source(w),
				         left, right, ev->xkey.time);
	break;

    case 2:			/* right */
	old = Text_CursorPos(w);
	MoveForwardChar(w, ev, params, np);

	DEBUGOUT(XdbDebug(__FILE__, w,
			  "KeySelection old %d new %d left %d right %d\n",
			  old, Text_CursorPos(w), left, right));

	if (old == Text_CursorPos(w))
	{
	    break;
	}

	if (sel)
	{			/* Already have a selection, extend it */
	    if (old == left)
	    {
		left = Text_CursorPos(w);
	    }

	    if (old == right)
	    {
		right = Text_CursorPos(w);
	    }
	}
	else
	{			/* New selection */
	    left = old;
	    right = Text_CursorPos(w);
	}
	(*Text_Source(w)->SetSelection) (Text_Source(w),
					 left, right, ev->xkey.time);
	break;

    case 3:			/* up */
	old = Text_CursorPos(w);
	MovePreviousLine(w, ev, params, np);

	DEBUGOUT(XdbDebug(__FILE__, w,
			  "KeySelection old %d new %d left %d right %d\n",
			  old, Text_CursorPos(w), left, right));

	if (old == Text_CursorPos(w))
	{
	    break;
	}

	if (sel)
	{			/* Already have a selection, extend it */
	    if (old == left)
	    {
		left = Text_CursorPos(w);
	    }

	    if (old == right)
	    {
		right = Text_CursorPos(w);
	    }
	}
	else
	{			/* New selection */
	    left = Text_CursorPos(w);
	    right = old;
	}
	(*Text_Source(w)->SetSelection) (Text_Source(w),
					 left, right, ev->xkey.time);
	break;

    case 4:			/* down */
	old = Text_CursorPos(w);
	MoveNextLine(w, ev, params, np);

	DEBUGOUT(XdbDebug(__FILE__, w,
			  "KeySelection old %d new %d left %d right %d\n",
			  old, Text_CursorPos(w), left, right));

	if (old == Text_CursorPos(w))
	{
	    break;
	}

	if (sel)
	{			/* Already have a selection, extend it */
	    if (old == left)
	    {
		left = Text_CursorPos(w);
	    }
	    if (old == right)
	    {
		right = Text_CursorPos(w);
	    }
	}
	else
	{			/* New selection */
	    left = old;
	    right = Text_CursorPos(w);
	}
	(*Text_Source(w)->SetSelection) (Text_Source(w),
					 left, right, ev->xkey.time);
	break;
    }
}

/*
 * KeySelection is the action routine for key-select.
 * Can either get called with no parameters,
 * or with "left", "right", "up", or "down". Any more ?
 */
static void
KeySelection(Widget w, XEvent *ev, String *params, Cardinal *num_params)
{
    int flag = 0;

    if (*num_params == 0)
    {
	DEBUGOUT(XdbDebug(__FILE__, w, "KeySelection()\n"));
    }
    else
    {
	DEBUGOUT(XdbDebug(__FILE__, w, "KeySelection(%s)\n", params[0]));
    }

    if (*num_params == 1)
    {
	if (strcmp(params[0], "left") == 0)
	{
	    flag = 1;
	}
	else if (strcmp(params[0], "right") == 0)
	{
	    flag = 2;
	}
#if 0
	else if (strcmp(params[0], "up") == 0)
	{
	    flag = 3;
	}
	else if (strcmp(params[0], "down") == 0)
	{
	    flag = 4;
	}
#endif
    }

    _KeySelection(w, ev, flag, params, num_params);
}

/*
 * ProcessShiftDown : extend the selection by another line
 */
static void
ProcessShiftDown(Widget w, XEvent *ev, String *params, Cardinal *num_params)
{
    DEBUGOUT(XdbDebug(__FILE__, w, "ProcessShiftDown\n"));

    _KeySelection(w, ev, 4, params, num_params);
}

static void
ProcessShiftUp(Widget w, XEvent *ev, String *params, Cardinal *num_params)
{
    DEBUGOUT(XdbDebug(__FILE__, w, "ProcessShiftUp\n"));

    _KeySelection(w, ev, 3, params, num_params);
}

static void
KillForwardChar(Widget w, XEvent *ev, String *params,
		Cardinal *num_params)
{
    DEBUGOUT(XdbDebug(__FILE__, w, "KillForwardChar\n"));

    DeleteForwardChar(w, ev, params, num_params);
}

static void
KillForwardWord(Widget w, XEvent *ev, String *params,
		Cardinal *num_params)
{
    DEBUGOUT(XdbDebug(__FILE__, w, "KillForwardWord\n"));

    DeleteForwardWord(w, ev, params, num_params);
}

static void
KillBackwardChar(Widget w, XEvent *ev, String *params,
		 Cardinal *num_params)
{
    DEBUGOUT(XdbDebug(__FILE__, w, "KillBackwardChar\n"));

    DeleteBackwardChar(w, ev, params, num_params);
}

static void
KillBackwardWord(Widget w, XEvent *ev, String *params,
		 Cardinal *num_params)
{
    DEBUGOUT(XdbDebug(__FILE__, w, "KillBackwardWord\n"));

    DeleteBackwardWord(w, ev, params, num_params);
}

static void
KillCurrentSelection(Widget w, XEvent *ev, String *params,
		     Cardinal *num_params)
{
    DEBUGOUT(XdbDebug(__FILE__, w, "KillCurrentSelection\n"));
}

static void
KillToEndOfLine(Widget w, XEvent *ev, String *params,
		Cardinal *num_params)
{
    DEBUGOUT(XdbDebug(__FILE__, w, "KillToEndOfLine\n"));

    DeleteToEndOfLine(w, ev, params, num_params);
}

static void
KillToStartOfLine(Widget w, XEvent *ev, String *params,
		  Cardinal *num_params)
{
    DEBUGOUT(XdbDebug(__FILE__, w, "KillToStartOfLine\n"));
    DeleteToStartOfLine(w, ev, params, num_params);
}

static void
MoveDestination(Widget w, XEvent *ev, String *params,
		Cardinal *num_params)
{
    DEBUGOUT(XdbDebug(__FILE__, w, "MoveDestination\n"));
}

static void
ProcessMove(Widget w, XEvent *ev, String *params,
	    Cardinal *num_params)
{
    DEBUGOUT(XdbDebug(__FILE__, w, "ProcessMove\n"));
}

static void
TraverseNextTabGroup(Widget w, XEvent *ev, String *params,
		     Cardinal *num_params)
{
    DEBUGOUT(XdbDebug(__FILE__, w, "TraverseNextTabGroup\n"));

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

static void
MoveNextLine(Widget aw, XEvent *ev, String *params, Cardinal *num_params)
{
    XmTextWidget w = (XmTextWidget)aw;
/* SG (15/08/1998) having these as unsigned gives erroneous results
   in the test index <= maxindex-2 when maxindex is 1
    unsigned int index, maxindex;
*/
    int index, maxindex;
    XmTextPosition pos = Text_CursorPos(w);

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

    index = _XmTextGetTableIndex(w, pos);
    if (index == (maxindex = Text_TotalLines(w) - 1))
    {
	pos = Text_LastPos(w);
    }
    else
    {
	pos += Text_LineTable(w)[index + 1].start_pos -
	    Text_LineTable(w)[index].start_pos;

	if (index <= maxindex - 2
	    && pos >= Text_LineTable(w)[index + 2].start_pos)
	{
	    pos = Text_LineTable(w)[index + 2].start_pos - 1;
	}
	else if (pos > Text_LastPos(w))
	{
	    pos = Text_LastPos(w);
	}
    }

    if (pos != Text_CursorPos(w))
    {
	(*Text_Output(w)->DrawInsertionPoint) (w, Text_CursorPos(w), off);
	_XmTextSetCursorPosition((Widget)w, pos);
    }
}


static void
MoveNextPage(Widget aw, XEvent *ev, String *params, Cardinal *num_params)
{
    XmTextWidget w = (XmTextWidget)aw;
    int index, maxindex;
    XmTextPosition pos = Text_CursorPos(w);
#ifndef BUG45
    int delta = Out_Rows(Text_OutputData(w));
#else
    int delta = Text_LineCount(w) - 1;
#endif

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

    index = _XmTextGetTableIndex(w, pos);
    maxindex = Text_TotalLines(w) - 1;

    if (index > maxindex - delta)
    {
	pos = Text_LastPos(w);
    }
    else
    {
	pos += Text_LineTable(w)[index + delta].start_pos -
	    Text_LineTable(w)[index].start_pos;

	if (index <= maxindex - delta - 1
	    && pos >= Text_LineTable(w)[index + delta + 1].start_pos)
	{
	    pos = Text_LineTable(w)[index + delta + 1].start_pos - 1;
	}
	else if (pos > Text_LastPos(w))
	{
	    pos = Text_LastPos(w);
	}
    }

    if (pos != Text_CursorPos(w))
    {
	(*Text_Output(w)->DrawInsertionPoint) (w, Text_CursorPos(w), off);
	_XmTextSetCursorPosition((Widget)w, pos);
    }
}

static void
InsertNewLine(Widget w, XEvent *ev, String *params, Cardinal *num_params)
{
    DEBUGOUT(XdbDebug(__FILE__, w, "InsertNewLine\n"));

    if (!Text_Editable(w))
    {
	return;			/* if we can't edit */
    }
    else if (Text_EditMode(w) == XmSINGLE_LINE_EDIT)
    {
	Activate(w, ev, params, num_params);
	return;
    }

    DoInsert((XmTextWidget)w, ev, "\n", 1);
}

static void
InsertNewLineAndBackup(Widget w, XEvent *ev, String *params, Cardinal *num_params)
{
    DEBUGOUT(XdbDebug(__FILE__, w, "InsertNewLineAndBackup\n"));

    if ((!Text_Editable(w)) || (Text_EditMode(w) == XmSINGLE_LINE_EDIT))
    {
	/* if we can't edit, or we are in single line only mode. */
	return;
    }

    DoInsert((XmTextWidget)w, ev, "\n", 1);
}

static void
InsertNewLineAndIndent(Widget w, XEvent *ev, String *params,
		       Cardinal *num_params)
{
    DEBUGOUT(XdbDebug(__FILE__, w, "InsertNewLineAndIndent\n"));

    if ((!Text_Editable(w)) || (Text_EditMode(w) == XmSINGLE_LINE_EDIT))
    {
	/* if we can't edit, or we are in single line only mode. */
	return;
    }
    else
    {
       XmTextBlockRec  block;
       XmTextPosition beginingOfLine, right;
       beginingOfLine = (*Text_Source(w)->Scan) (Text_Source(w),
                               Text_CursorPos(w), XmSELECT_LINE,  XmsdLeft, 1, False);
       right = (*Text_Source(w)->Scan) (Text_Source(w), beginingOfLine,
                               XmSELECT_WHITESPACE, XmsdRight,
                               Text_CursorPos(w) - beginingOfLine, /* so we do not select more
                                                                      whitespace than just this line */
                               False);

               /* passing "beginingOfLine - 1" should mean we also get the newline :-) */
       (*Text_Source(w)->ReadSource) (Text_Source(w), beginingOfLine - 1, right, &block);
       DoInsert((XmTextWidget)w, ev, block.ptr , block.length );
       XtFree(block.ptr);
    }
}

static void
MovePageLeft(Widget w, XEvent *ev, String *params, Cardinal *num_params)
{
    DEBUGOUT(XdbDebug(__FILE__, w, "MovePageLeft\n"));
}

static void
MovePageRight(Widget w, XEvent *ev, String *params, Cardinal *num_params)
{
    DEBUGOUT(XdbDebug(__FILE__, w, "MovePageRight\n"));
}

static void
PasteClipboard(Widget w, XEvent *ev, String *params, Cardinal *num_params)
{
    DEBUGOUT(XdbDebug(__FILE__, w, "PasteClipboard\n"));
    XmTextPaste(w);
}

static void
TraversePrevTabGroup(Widget w, XEvent *ev, String *params, Cardinal *num_params)
{
    DEBUGOUT(XdbDebug(__FILE__, w, "TraversePrevTabGroup\n"));

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


static void
MovePreviousLine(Widget aw, XEvent *ev, String *params, Cardinal *num_params)
{
    XmTextWidget w = (XmTextWidget)aw;
    unsigned int index;
    XmTextPosition pos = Text_CursorPos(w);

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

    index = _XmTextGetTableIndex(w, pos);
    if (index == 0)
    {
	pos = Text_FirstPos(w);
    }
    else
    {
	pos += Text_LineTable(w)[index - 1].start_pos -
	    Text_LineTable(w)[index].start_pos;

	if (pos >= Text_LineTable(w)[index].start_pos)
	{
	    pos = Text_LineTable(w)[index].start_pos - 1;
	}
    }
    if (pos != Text_CursorPos(w))
    {
	(*Text_Output(w)->DrawInsertionPoint) (w, Text_CursorPos(w), off);

	_XmTextSetCursorPosition((Widget)w, pos);
    }
}


static void
MovePreviousPage(Widget aw, XEvent *ev, String *params, Cardinal *num_params)
{
    XmTextWidget w = (XmTextWidget)aw;
    unsigned int index;
    XmTextPosition pos = Text_CursorPos(w);
#ifndef BUG45
    int delta = Out_Rows(Text_OutputData(w));
#else
    int delta = Text_LineCount(w) - 1;
#endif

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

    index = _XmTextGetTableIndex(w, pos);
    if (index < delta)
    {
	pos = Text_FirstPos(w);
    }
    else
    {
	pos += Text_LineTable(w)[index - delta].start_pos -
	    Text_LineTable(w)[index].start_pos;

	if (pos >= Text_LineTable(w)[index - delta + 1].start_pos)
	{
	    pos = Text_LineTable(w)[index - delta + 1].start_pos - 1;
	}
    }
    if (pos != Text_CursorPos(w))
    {
	(*Text_Output(w)->DrawInsertionPoint) (w, Text_CursorPos(w), off);

	_XmTextSetCursorPosition((Widget)w, pos);
    }
}

static void
ProcessBDrag(Widget w, XEvent *ev, String *params, Cardinal *num_params)
{
    DEBUGOUT(XdbDebug(__FILE__, w, "ProcessBDrag\n"));
}

static void
ProcessDown(Widget w, XEvent *ev, String *params, Cardinal *num_params)
{
    DEBUGOUT(XdbDebug(__FILE__, w, "ProcessDown\n"));

    MoveNextLine(w, ev, params, num_params);
}

static void
ProcessHome(Widget w, XEvent *ev, String *params,
	    Cardinal *num_params)
{
    DEBUGOUT(XdbDebug(__FILE__, w, "ProcessHome\n"));

    MoveToLineStart(w, ev, params, num_params);
}

static void
ProcessReturn(Widget w, XEvent *ev, String *params, Cardinal *num_params)
{
    DEBUGOUT(XdbDebug(__FILE__, w, "ProcessReturn\n"));

    InsertNewLine(w, ev, params, num_params);
}

static void
ProcessTab(Widget w, XEvent *ev, String *params, Cardinal *num_params)
{
    DEBUGOUT(XdbDebug(__FILE__, w, "ProcessTab\n"));
    if (Text_EditMode(w) == XmSINGLE_LINE_EDIT)
    {
    	_XmMgrTraversal(w, XmTRAVERSE_NEXT_TAB_GROUP);
    }
    else
    {
    	DoInsert((XmTextWidget)w, ev, "\t", 1);
    }
}

static void
ProcessUp(Widget w, XEvent *ev, String *params, Cardinal *num_params)
{
    DEBUGOUT(XdbDebug(__FILE__, w, "ProcessUp\n"));

    MovePreviousLine(w, ev, params, num_params);
}

static void
RedrawDisplay(Widget w, XEvent *ev, String *params, Cardinal *num_params)
{
    xmTextClassRec.core_class.expose(w, NULL, (Region)NULL);
}

static void
ScrollOneLineUp(Widget w, XEvent *ev, String *params, Cardinal *num_params)
{
    DEBUGOUT(XdbDebug(__FILE__, w, "ScrollOneLineUp\n"));
    XmTextScroll(w, -1);
}

static void
SecondaryAdjust(Widget w, XEvent *ev, String *params, Cardinal *num_params)
{
    DEBUGOUT(XdbDebug(__FILE__, w, "SecondaryAdjust\n"));
}

static void
SecondaryNotify(Widget w, XEvent *ev, String *params, Cardinal *num_params)
{
    DEBUGOUT(XdbDebug(__FILE__, w, "SecondaryNotify\n"));
}

static void
SecondaryStart(Widget w, XEvent *ev, String *params, Cardinal *num_params)
{
    DEBUGOUT(XdbDebug(__FILE__, w, "SecondaryStart\n"));
}

static void
SelectAll(Widget w, XEvent *ev, String *params, Cardinal *num_params)
{
    DEBUGOUT(XdbDebug(__FILE__, w, "SelectAll\n"));
}

static void
StartExtendSelection(Widget w, XEvent *ev, String *params, Cardinal *num_params)
{
    DEBUGOUT(XdbDebug(__FILE__, w, "StartExtendSelection\n"));

    DoGrabFocus(w, ev, params, num_params);
}



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

    DEBUGOUT(XdbDebug(__FILE__, w, "SelfInsert"));

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

    if (XdbInDebug(__FILE__, w))
    {
	DEBUGOUT(XdbDebug(__FILE__, w, "XmImMbLookupString => %d\n", len));
	DEBUGOUT(XdbDebug0(__FILE__, w, "\tStatus %s\n",
			   (status == XLookupNone) ? "none" :
			   (status == XLookupChars) ? "chars" :
			   (status == XLookupBoth) ? "both" :
			   (status == XLookupKeySym) ? "keysym" :
			   (status == XBufferOverflow) ? "overflow" : "????"));

	if (status == XLookupBoth || status == XLookupKeySym)
	{
	    DEBUGOUT(XdbDebug0(__FILE__, w, "\tKeySym 0x%X\n", keysym));
	}

	if (len > 0)
	{
	    int i;

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

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

/* This is the insertion point for secondary selections */
static void
SetAnchor(Widget w, XEvent *ev, String *params, Cardinal *num_params)
{
    DEBUGOUT(XdbDebug(__FILE__, w, "SetAnchor\n"));

    Text_DestPosition(w) = (*Text_Output(w)->XYToPos)
	((XmTextWidget)w, ev->xbutton.x, ev->xbutton.y);
}

static void
SetCursorPosition(Widget w, XEvent *ev, String *params, Cardinal *num_params)
{
    DEBUGOUT(XdbDebug(__FILE__, w, "SetCursorPosition\n"));
}

static void
SetSelectionHint(Widget w, XEvent *ev, String *params, Cardinal *num_params)
{
    DEBUGOUT(XdbDebug(__FILE__, w, "SetSelectionHint\n"));
}

static void
ScrollCursorVertically(Widget w, XEvent *ev, String *params, Cardinal *num_params)
{
    DEBUGOUT(XdbDebug(__FILE__, w, "ScrollCursorVertically\n"));
}


static void
ScrollOneLineDown(Widget w, XEvent *ev, String *params, Cardinal *num_params)
{
    DEBUGOUT(XdbDebug(__FILE__, w, "ScrollOneLineDown\n"));
    XmTextScroll(w, 1);
}

static void
ToggleAddMode(Widget w, XEvent *ev, String *params, Cardinal *num_params)
{
    DEBUGOUT(XdbDebug(__FILE__, w, "ToggleAddMode\n"));
    Text_AddMode(w) = ! Text_AddMode(w);
}


static void
ToggleOverstrike(Widget w, XEvent *ev, String *params, Cardinal *num_params)
{
    DEBUGOUT(XdbDebug(__FILE__, w, "ToggleOverstrike\n"));
    Text_InputData(w) -> overstrike = ! Text_InputData(w) -> overstrike ;
}

static void
TextLeave(Widget w, XEvent *ev, String *params, Cardinal *num_params)
{
    DEBUGOUT(XdbDebug(__FILE__, w, "TextLeave\n"));
}

static void
TraverseHome(Widget w, XEvent *ev, String *params, Cardinal *num_params)
{
    DEBUGOUT(XdbDebug(__FILE__, w, "TraverseHome\n"));

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

static void
TraverseDown(Widget w, XEvent *ev, String *params, Cardinal *num_params)
{
    DEBUGOUT(XdbDebug(__FILE__, w, "TraverseDown\n"));

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

static void
TraverseUp(Widget w, XEvent *ev, String *params, Cardinal *num_params)
{
    DEBUGOUT(XdbDebug(__FILE__, w, "TraverseUp\n"));

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

static void
TextFocusIn(Widget w, XEvent *ev, String *params, Cardinal *num_params)
{
    XmTextVerifyCallbackStruct cbs;
    OutputData o = Text_OutputData(w);

    DEBUGOUT(XdbDebug(__FILE__, w, "TextFocusIn"));

    if (Text_Editable(w))
    {
	XmImSetFocusValues(w, NULL, 0);
    }

    if (!Out_HasFocus(o))
    {
	if (Text_FocusCallback(w))
	{
	    cbs.reason = XmCR_FOCUS;
	    cbs.event = ev;
	    cbs.currInsert = cbs.newInsert = Text_CursorPos(w);
	    cbs.startPos = cbs.endPos = 0;
	    cbs.text = NULL;

	    XtCallCallbackList((Widget)w, Text_FocusCallback(w), &cbs);
	}

	Out_HasFocus(o) = True;
    }

    /*
     * 980827 - pgw@hungry.com: Fix for highlight defect.
     */
    XtCallActionProc((Widget)w, "PrimitiveFocusIn", ev,
			 params, *num_params);

}

static void
TextFocusOut(Widget w, XEvent *ev, String *params, Cardinal *num_params)
{
    XmTextVerifyCallbackStruct cbs;
    OutputData o = Text_OutputData(w);

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

    if (Text_Editable(w))
    {
	XmImUnsetFocus(w);
    }

    if (Out_HasFocus(o))
    {
	if (Text_LosingFocusCallback(w))
	{
	    cbs.reason = XmCR_LOSING_FOCUS;
	    cbs.event = ev;
	    cbs.currInsert = cbs.newInsert = Text_CursorPos(w);
	    cbs.startPos = cbs.endPos = 0;
	    cbs.text = NULL;

	    XtCallCallbackList((Widget)w, Text_LosingFocusCallback(w), &cbs);
	}

	Out_HasFocus(o) = False;
    }
    /*
     * 980827 - pgw@hungry.com: Fix for highlight defect.
     */
    XtCallActionProc((Widget)w, "PrimitiveFocusOut", ev,
			 params, *num_params);

}

static void
UnKill(Widget w, XEvent *ev, String *params, Cardinal *num_params)
{
    DEBUGOUT(XdbDebug(__FILE__, w, "UnKill\n"));
}

static void
VoidAction(Widget w, XEvent *ev, String *params, Cardinal *num_params)
{
    DEBUGOUT(XdbDebug(__FILE__, w, "VoidAction\n"));
}


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


Widget
_XmTextGetDropReciever(Widget w)
{
    /* FIX ME */
    return w;
}

Boolean
_XmTextHasDestination(Widget w)
{
    /* FIX ME */
    return False;
}

void
_XmTextInputGetSecResData(XmSecondaryResourceData *secResDataRtn)
{
}

XmTextPosition
_XmTextGetAnchor(XmTextWidget tw)
{
    InputData i = Text_InputData(tw);
    return In_HighlightPivot(i);
}

Boolean
_XmTextSetDestinationSelection(Widget w,
			       XmTextPosition position,
			       Boolean disown,
			       Time set_time)
{
    /* FIX ME */
    return False;
}

Boolean
_XmTextSetSel2(XmTextWidget tw,
	       XmTextPosition left,
	       XmTextPosition right,
	       Time set_time)
{
    /*CP: first attempt */
    InputData inp = Text_InputData(tw);

    if ( left < 0 ) 
		/*CP: it seems Motif does not do this check ! 
		|| right > Text_LastPos(tw) ) */
	return False;

    inp -> sel2Left = left;
    inp -> sel2Right = right;
    inp -> hasSel2 = True;
    inp -> sec_time = set_time;
    return True;
}

Boolean
_XmTextGetSel2(XmTextWidget tw,
	       XmTextPosition *left,
	       XmTextPosition *right)
{
    InputData inp = Text_InputData(tw);
    if ( ! inp -> hasSel2 )
	return False;

    *left = inp -> sel2Left ;
    *right = inp -> sel2Right ;
    return True;
}
