Logo Search packages:      
Sourcecode: lesstif1-1 version File versions  Download package

TextIn.c

/**
 *
 * $Header: /cvsroot/lesstif/lesstif/lib/Xm/TextIn.c,v 1.81 2003/08/21 13:47:52 dannybackx Exp $
 *
 * Copyright (C) 1995 Free Software Foundation, Inc.
 * Copyright  1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 LessTif Development Team
 *
 * 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/lesstif/lesstif/lib/Xm/TextIn.c,v 1.81 2003/08/21 13:47:52 dannybackx Exp $";

#include <LTconfig.h>

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include <X11/Xatom.h>

#include <Xm/XmP.h>
#include <Xm/TextP.h>
#include <Xm/TextOutP.h>
#if XmVERSION > 1
#include <Xm/XmIm.h>
#endif

#include <XmI/XmI.h>

#include <Xm/AtomMgr.h>
#include <Xm/DragC.h>
#include <Xm/DropSMgr.h>
#include <Xm/DropTrans.h>
#include <XmI/AtomMgrI.h>
#include <XmI/DragDropI.h>

#include <XmI/DebugUtil.h>


#ifdef Out_FontTextWidth 
#undef Out_FontTextWidth
#endif
#define Out_FontTextWidth(o,s,l)  (int)_XmOut_FontTextWidth(o, s, l)


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);

static Boolean drag_convert_proc(Widget w, Atom *selection,
                         Atom *target, Atom *type_return,
                         XtPointer *value_return,
                         unsigned long *length_return,
                         int *format_return);
static void drag_transfer_proc(Widget dw, XtPointer client, Atom *selection,
                         Atom *type,
                         XtPointer value,
                         unsigned long *length,
                         int *format);
static void drag_drop_finish(Widget w,
                       XtPointer client_data,
                       XtPointer call_data);

static void _KeySelection(Widget w, XEvent *ev, int flag,
                          String *params, Cardinal *np);

#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(_LtDebug(__FILE__, w, "InputGetValues :\n"));

    _LtDebugPrintArgList(__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_w,
             ArgList args, Cardinal *num_args)
{
    DEBUGOUT(_LtDebug(__FILE__, new_w, "InputSetValues :\n"));

    DEBUGOUT(_LtDebugPrintArgList(__FILE__, new_w, 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(_LtDebug(__FILE__, aw, "InputDestroy\n"));

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

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

static void
GetSecResData(XmSecondaryResourceData *secres)
{
}

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


extern 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));
    memcpy(Text_Input(w), &inputRec, 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;
    i->overstrike = False;

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

    DEBUGOUT(_LtDebugPrintArgList(__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(_LtDebug(__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);
    }
}

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

/*    printf("_XmTextDelete - %li %li\n", start, end); */
    if (end <= 0)
    {
      end = 0;
    }

    if ( start > end )
    {
      XmTextPosition tmp = start;
      start = end;
      end = tmp;
    }
    blockrec.ptr = NULL;
    blockrec.length = 0;
    blockrec.format = XmFMT_8_BIT;

    cbs.reason = XmCR_MODIFYING_TEXT_VALUE;
    cbs.event = ev;
/*CP: when doing a delete-previous-char these are not the same. Is this true for other actions ? */
/*    cbs.startPos = cbs.newInsert = start; */
    cbs.startPos = start;
    if (Text_CursorPos(w) <= start) {
      cbs.newInsert = Text_CursorPos(w);
    } else if ( Text_CursorPos(w) + ( end - start ) > Text_LastPos(w) )
    {
      /*CP: WE do not want to new insertion position to be past the end. */
      cbs.newInsert = Text_CursorPos(w) - ( end - start ) ;

      if (cbs.newInsert < 0)
            cbs.newInsert = 0;      /* Bug # 721010 */
    }
    else
    {
      /* rws 4 Mar 2000
         This is wrong in the case of delete-previous-character. Think about
         it, if you are at position 1 and do a delete-previous, you should
         end up at position 0. Is the other half of this if not always
         correct??
      */
      /*
      cbs.newInsert = Text_CursorPos(w);
      */
      cbs.newInsert = Text_CursorPos(w) - ( end - start ) ;

      /* Danny 17 mar 2000 don't go below position 0 */
      if (cbs.newInsert < 0)
            cbs.newInsert = 0;
    }
    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, False);

      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
           */
#if 1
          /* CP:17 May 1999: this does not seem to be needed */
          _XmTextUpdateLineTable((Widget)w, cbs.startPos,
                           cbs.endPos, &blockrec, True);
#endif
          _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, startInsert;

    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;
        startInsert = left ;
        cbs.newInsert = cbs.currInsert;
    } else if (Text_InputData(w)->overstrike) {
      DEBUGOUT(_LtDebug(__FILE__, (Widget)w, "DoInsert overstrike\n"));
        cbs.currInsert = cbs.startPos = cbs.endPos = Text_CursorPos(w);
        startInsert = cbs.currInsert ;
        cbs.newInsert = cbs.currInsert;
      /*
       * Implement the overstrike rules :
       *    - insert if at the end of a line,
       *    - overwrite otherwise
       */
      if (1) {    /* FIX ME */
            cbs.endPos ++;
      }
    } else {
        cbs.currInsert = cbs.startPos = cbs.endPos = Text_CursorPos(w);
        startInsert = cbs.currInsert ;
        cbs.newInsert = cbs.currInsert;
    }

    DEBUGOUT(_LtDebug(__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(_LtDebug(__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, False);

      if (status == EditDone && blockrec.length > 0 )
      {
          _XmTextSetCursorPosition(aw, startInsert + blockrec.length );
      }
    }
    Text_PendingOff(w) = False; 
    (*Text_Output(w)->DrawInsertionPoint) (w, Text_CursorPos(w), on );

    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(_LtDebug(__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(_LtDebug(__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(_LtDebug(__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(_LtDebug(__FILE__, (Widget)w,
                    "DoScanType: XmSELECT_OUT_LINE\n"));
      break;
#endif

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

      DEBUGOUT(_LtDebug(__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(_LtDebug(__FILE__, (Widget)w, "DoScanType: ???\n"));

      break;
    }
}

static void DoUnselectionBecauseOfKeyNavigation(Widget w, XEvent *ev)
{
    if ( _XmStringSourceHasSelection(GetSrc(w)) )
    {
      XmTextSetSelection(w,-1,-1,ev->xkey.time);
    }
}

/* 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(_LtDebug(__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(_LtDebug(__FILE__, w, "MoveBackwardChar\n"));
    if (! Text_AddMode(w))
      DoUnselectionBecauseOfKeyNavigation(w,ev);
    if (Text_CursorPos(w) > 0)
    {
        OutputData o = Text_OutputData((XmTextWidget)w);
        XmTextPosition pos;
        char *ptr;
        int     next, i;

        ptr = Text_Source(w)->data->ptr;

        next = Out_FontTextWidth(o, ptr, Text_CursorPos(w)-1);
        pos = Text_CursorPos(w)-1;
        for(i=Text_CursorPos(w)-2; i>=0; i--){
            if (next > Out_FontTextWidth(o, ptr, i)){
                pos = i + 1;
                break;
            }
            if (next == Out_FontTextWidth(o, ptr, i)){
                pos = i;
            }
        }

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

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

    if (! Text_AddMode(w))
      DoUnselectionBecauseOfKeyNavigation(w,ev);
    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);

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

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

    if (! Text_AddMode(w))
      DoUnselectionBecauseOfKeyNavigation(w,ev);
    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);

      _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(_LtDebug(__FILE__, w, "MoveBeginningOfFile"));

    if (! Text_AddMode(w))
      DoUnselectionBecauseOfKeyNavigation(w,ev);
    if (Text_CursorPos(w) > 0)
    {
      _XmTextSetCursorPosition(w, 0);
    }
}

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

    
    if (*num_params==1 && !strcmp("extend", *params)) {
       DEBUGOUT(_LtDebug(__FILE__, w, "MoveToLineStart(extend)"));
       _KeySelection(w, ev, 3, params, num_params);   
    } else {
       DEBUGOUT(_LtDebug(__FILE__, w, "MoveToLineStart"));
       if (! Text_AddMode(w))
      DoUnselectionBecauseOfKeyNavigation(w,ev);
       pos = (*Text_Source(w)->Scan) (Text_Source(w), Text_CursorPos(w),
                           XmSELECT_LINE, XmsdLeft, 1, False);
       _XmTextSetCursorPosition(w, pos);
    }
}

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

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

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

/* For Selection */
typedef struct {
    XEvent  *ev;
    int           use_ctext;
} SelectionClientData;

/*
 * _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)
{
    SelectionClientData *client_data = (SelectionClientData*)client;
    XEvent *ev = (XEvent*)client_data->ev;

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

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

          if (s)
          {
            if (*selection == XA_SECONDARY)
            {
                    XTextProperty prop;
                    int count, i;
                    char **list;

                    if (*type == XA_STRING){
                        char *buf;

                        buf = XtMalloc(*len + 1);
                        strncpy(buf, (char *)value, *len);
                        buf[*len] = '\0';

                        XmbTextListToTextProperty(XtDisplay(w), &buf, 1,
                                XCompoundTextStyle, &prop);

                        XtFree(buf);
                    }else{
                        prop.value = (unsigned char *)value;
                        prop.encoding = *type;
                        prop.format = *format;
                        prop.nitems = *len;
                    }

                    XmbTextPropertyToTextList(XtDisplay(w), &prop, &list, &count);

                    for(i=0; i<count; i++){
                        DoInsert((XmTextWidget)w, ev, list[i], strlen(list[i]));
                    }
            }
            else
            {
            XmTextPosition pos;

                pos = (*Text_Output(w)->XYToPos)((XmTextWidget)w,
                              ev->xbutton.x, ev->xbutton.y);
                XmTextSetCursorPosition(w, pos);
                    {
                        XTextProperty prop;
                        int count, i;
                        char **list;

                        if (*type == XA_STRING){
                            char *buf;

                            buf = XtMalloc(*len + 1);
                            strncpy((char *)buf, value, *len);
                            buf[*len] = '\0';

                            XmbTextListToTextProperty(XtDisplay(w), &buf, 1,
                                        XCompoundTextStyle, &prop);

                            XtFree(buf);
                        }else{
                            prop.value = (unsigned char *)value;
                            prop.encoding = *type;
                            prop.format = *format;
                            prop.nitems = *len;
                        }

                        XmbTextPropertyToTextList(XtDisplay(w), &prop, &list, &count);

                        for(i=0; i<count; i++){
                            DoInsert((XmTextWidget)w, ev, list[i], strlen(list[i]));
                        }
                    }
            }
          }
      }
      XtFree((char *)value);
      XtFree((char *)client);
    }
}

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

    if (Text_Editable(w))
    {
        SelectionClientData *client_data;

        client_data = XtNew(SelectionClientData);
        client_data->ev = XtNew(XEvent);

        *client_data->ev = *ev;
        client_data->use_ctext = 1;

      Text_PendingOff(w)= True;
        XtGetSelectionValue(w, XA_SECONDARY,
                        XmInternAtom(XtDisplay(w), "COMPOUND_TEXT", False),
                        _XmTextGetSelection,
                        (XtPointer)client_data , ev->xbutton.time);
    }
}

static void
ProcessCancel(Widget w, XEvent *ev, String *params, Cardinal *num_params)
{
    DEBUGOUT(_LtDebug(__FILE__, w, "ProcessCancel\n"));
    /* rws 15 Jan 2000
       There is more to it than this. It needs to cancel some operations that
       may be in progress, otherwise do this. Look at the man page.
     */
    if (XmIsManager(XtParent(w)))
    {
      XtCallActionProc(XtParent(w), "ManagerParentCancel", ev, params, *num_params);
    }
}

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

static void
CutPrimary(Widget w, XEvent *ev, String *params, Cardinal *num_params)
{
    DEBUGOUT(_LtDebug(__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(_LtDebug(__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))
    {
        OutputData o = Text_OutputData((XmTextWidget)w);
        XmTextPosition pos;
        char    *ptr;
        int     curr, i;

        ptr = Text_Source(w)->data->ptr;
        curr = Out_FontTextWidth(o, ptr, Text_CursorPos(w));
        pos = Text_CursorPos(w);
        for(i=Text_CursorPos(w)+1; i<=Text_LastPos(w); i++){
            if (curr < Out_FontTextWidth(o, ptr, i)){
                pos = i;
                break;
            }
        }

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

static void
DeleteBackwardChar(Widget w, XEvent *ev, String *params,
               Cardinal *num_params)
{
    Boolean sel;
    XmTextPosition left, right;
    DEBUGOUT(_LtDebug(__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)
    {
      /*CP: we have to reset the selection */
      (*Text_Source(w)->SetSelection) (Text_Source(w), right, right, ev->xkey.time);
      _XmTextDelete((XmTextWidget)w,ev,left,right);
    }
    else if (Text_CursorPos(w) > 0)
    {
        OutputData o = Text_OutputData((XmTextWidget)w);
        XmTextPosition pos;
        char    *ptr;
        int     next, i;

        ptr = Text_Source(w)->data->ptr;
        next = Out_FontTextWidth(o, ptr, Text_CursorPos(w)-1);
        pos = Text_CursorPos(w)-1;
        for(i=Text_CursorPos(w)-2; i>=0; i--){
            if (next > Out_FontTextWidth(o, ptr, i)){
                pos = i + 1;
                break;
            }
            if (next == Out_FontTextWidth(o, ptr, i)){
                pos = i;
            }
        }

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

static void
DeleteForwardWord(Widget w, XEvent *ev, String *params, Cardinal *num_params)
{
    Boolean sel;
    XmTextPosition left, right;
    DEBUGOUT(_LtDebug(__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(_LtDebug(__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(_LtDebug(__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(_LtDebug(__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(_LtDebug(__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(_LtDebug(__FILE__, w, "DeselectAll\n"));
    (*Text_Source(w)->SetSelection)(Text_Source(w),1,0,ev->xkey.time);
}


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


    if (*num_params==1 && !strcmp("extend", *params)) {
        DEBUGOUT(_LtDebug(__FILE__, w, "MoveToLineEnd(extend)"));
        _KeySelection(w, ev, 4, params, num_params);   
    } else
    {
        DEBUGOUT(_LtDebug(__FILE__, w, "MoveToLineEnd"));
        if (! Text_AddMode(w))
      DoUnselectionBecauseOfKeyNavigation(w,ev);
        pos = (*Text_Source(w)->Scan) (Text_Source(w), Text_CursorPos(w),
                           XmSELECT_LINE, XmsdRight, 1, False);
        _XmTextSetCursorPosition(w, pos);
     }
}

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

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

    if (! Text_AddMode(w))
      DoUnselectionBecauseOfKeyNavigation(w,ev);
    pos = Text_LastPos(w);

    _XmTextSetCursorPosition(w, pos);
}


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

    DEBUGOUT(_LtDebug(__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(_LtDebug(__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, cursor_pos;
    XmTextScanType st;
    InputData i = Text_InputData(w);
    Boolean sel;

    Text_InputData(w) -> select_pos_y = ev->xbutton.y ;
    Text_InputData(w) -> select_pos_x = ev->xbutton.x ;

    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(_LtDebug(__FILE__, w,
            "ExtendSelection (pos %d, origleft %d) existing sel. %d-%d\n",
            pos, In_HighlightPivot(i), left, right));
    } else {
      DEBUGOUT(_LtDebug(__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);
      }
      cursor_pos = 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);
      }
      cursor_pos = left;
    }

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

    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(_LtDebug(__FILE__, w, "MoveForwardChar\n"));

    if (! Text_AddMode(w))
      DoUnselectionBecauseOfKeyNavigation(w,ev);
    if (Text_CursorPos(w) < Text_LastPos(w))
    {
        OutputData o = Text_OutputData((XmTextWidget)w);
        XmTextPosition pos;
        char *ptr;
        int     curr, i;

        ptr = Text_Source(w)->data->ptr;
        curr = Out_FontTextWidth(o, ptr, Text_CursorPos(w));
        pos = Text_CursorPos(w);
        for(i=Text_CursorPos(w)+1; i<=Text_LastPos(w); i++){
            if (curr < Out_FontTextWidth(o, ptr, i)){
                pos = i;
                break;
            }
        }

        _XmTextSetCursorPosition(w, pos);
    }
}

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

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

    if (! Text_AddMode(w))
      DoUnselectionBecauseOfKeyNavigation(w,ev);
    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);

    _XmTextSetCursorPosition(w, pos);
}


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

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

    if (! Text_AddMode(w))
      DoUnselectionBecauseOfKeyNavigation(w,ev);
    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);

    _XmTextSetCursorPosition(w, pos);
}

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

    DEBUGOUT(_LtDebug(__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(_LtDebug(__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);

    if ( ! sel )
    {
      In_HighlightPivot( Text_InputData(w) ) = Text_CursorPos(w) ;
    }

    old = Text_CursorPos(w);

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

      DEBUGOUT(_LtDebug(__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 */
      MoveForwardChar(w, ev, params, np);

      DEBUGOUT(_LtDebug(__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 */
      MovePreviousLine(w, ev, params, np);

      DEBUGOUT(_LtDebug(__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 */
      MoveNextLine(w, ev, params, np);

      DEBUGOUT(_LtDebug(__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(_LtDebug(__FILE__, w, "KeySelection()\n"));
    }
    else
    {
      DEBUGOUT(_LtDebug(__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(_LtDebug(__FILE__, w, "ProcessShiftDown\n"));

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

static void
TraverseNextTabGroup(Widget w, XEvent *ev, String *params,
                 Cardinal *num_params)
{
    DEBUGOUT(_LtDebug(__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(_LtDebug(__FILE__, aw, "MoveNextLine\n"));
    if (! Text_AddMode(w))
      DoUnselectionBecauseOfKeyNavigation(aw,ev);

    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))
    {
      _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(_LtDebug(__FILE__, aw, "MoveNextPage"));
    if (! Text_AddMode(w))
      DoUnselectionBecauseOfKeyNavigation(aw,ev);

    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))
    {
      _XmTextSetCursorPosition((Widget)w, pos);
    }
}

static void
InsertNewLine(Widget w, XEvent *ev, String *params, Cardinal *num_params)
{
    DEBUGOUT(_LtDebug(__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(_LtDebug(__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(_LtDebug(__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(_LtDebug(__FILE__, w, "MovePageLeft\n"));
    if (! Text_AddMode(w))
      DoUnselectionBecauseOfKeyNavigation(w,ev);
}

static void
MovePageRight(Widget w, XEvent *ev, String *params, Cardinal *num_params)
{
    DEBUGOUT(_LtDebug(__FILE__, w, "MovePageRight\n"));
    if (! Text_AddMode(w))
      DoUnselectionBecauseOfKeyNavigation(w,ev);
}

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

static void
TraversePrevTabGroup(Widget w, XEvent *ev, String *params, Cardinal *num_params)
{
    DEBUGOUT(_LtDebug(__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(_LtDebug(__FILE__, aw, "MovePreviousLine\n"));

    if (! Text_AddMode(w))
      DoUnselectionBecauseOfKeyNavigation(aw,ev);
    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))
    {
      _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
    Cardinal delta = Out_Rows(Text_OutputData(w));
#else
    Cardinal delta = Text_LineCount(w) - 1;
#endif

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

    if (! Text_AddMode(w))
      DoUnselectionBecauseOfKeyNavigation(aw,ev);
    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))
    {
      _XmTextSetCursorPosition((Widget)w, pos);
    }
}

static void
ProcessBDrag(Widget w, XEvent *ev, String *params, Cardinal *num_params)
{
    Atom export_target[3];
    Arg args[10];
    int n = 0;
    Widget dc;
    XmTextPosition position;
    XmSourceData d = Text_Source(w)->data;

    _XmObjectLock(w);
    DEBUGOUT(_LtDebug(__FILE__, w, "ProcessBDrag\n"));

    /* If widget has no selection or cursor is not in selection,
       then return. */
    position = (*Text_Output(w)->XYToPos)((XmTextWidget)w, 
                  ev->xbutton.x, ev->xbutton.y);

    if (!d->hasselection ||
      position < d->left ||
      position >= d->right)
    {

      _XmObjectUnlock(w);
      return;
    }

    /* set up some stuff */
    export_target[0] = XmInternAtom(XtDisplay(w), _XA_COMPOUND_TEXT, False);
    export_target[1] = XmInternAtom(XtDisplay(w), _XA_TEXT, False);
    export_target[2] = XA_STRING;

    XtSetArg(args[n], XmNexportTargets, export_target); n++;
    XtSetArg(args[n], XmNnumExportTargets, 3); n++;
    XtSetArg(args[n], XmNdragOperations, XmDROP_COPY|XmDROP_MOVE); n++;
    XtSetArg(args[n], XmNclientData, w); n++;
    XtSetArg(args[n], XmNconvertProc, drag_convert_proc); n++;
    XtSetArg(args[n], XmNsourceCursorIcon, _XmGetTextualDragIcon(w)); n++;

    dc = XmDragStart(w, ev, args, n);

    if (dc)
    {
      XtAddCallback(dc, XmNdragDropFinishCallback, drag_drop_finish, NULL);
    }
    _XmObjectUnlock(w);
}

static void
drag_drop_finish(Widget w, XtPointer client_data, XtPointer call_data)
{
    DEBUGOUT(_LtDebug(__FILE__, w, "%s:drag_drop_finish(%d)\n",
      __FILE__, __LINE__));
}

static Boolean
drag_convert_proc(Widget w, Atom *selection,
              Atom *target, Atom *type_return,
              XtPointer *value_return,
              unsigned long *length_return,
              int *format_return)
{
    XmSourceData d;
    XmTextPosition left, right;
    Boolean sel;
    Widget src;
    Atom atom_comp_text;
    Atom atom_text;
    Atom atom_motif_drop;
    Atom atom_delete;

    atom_comp_text =  XmInternAtom(XtDisplay(w), _XA_COMPOUND_TEXT, False);
    atom_text = XmInternAtom(XtDisplay(w), _XA_TEXT, False);
    atom_motif_drop =  XmInternAtom(XtDisplay(w), _XA_MOTIF_DROP, False);
    atom_delete =  XmInternAtom(XtDisplay(w), _XA_DELETE, False);

    if (*selection != atom_motif_drop)
    {
      DEBUGOUT(_LtDebug(__FILE__, w, "selection is not MOTIF_DROP\n"));
      return False;
    }

    DEBUGOUT(_LtDebug(__FILE__, w, "We're dealing with MOTIF_DROP\n"));

    XtVaGetValues(w, XmNclientData, &src, NULL);
    d = Text_Source(src)->data;
    _XmObjectLock(src);
 
    if (*target == XA_STRING){
        *length_return = (long)(d->right - d->left);
        *value_return = XtMalloc(d->right - d->left + 1);
      strncpy((char *)*value_return, &d->ptr[d->left], d->right - d->left);
        *type_return = XA_STRING;
    }
    else if (*target == atom_comp_text || *target == atom_text){

          XTextProperty prop;
          char *buf;
          int ret;

          buf = XtMalloc(d->right - d->left + 1);
            strncpy(buf, &d->ptr[d->left], d->right - d->left);
          buf[d->right - d->left] = '\0';

          ret = XmbTextListToTextProperty(XtDisplay(src), &buf, 1,
                        XCompoundTextStyle, &prop);
            
          XtFree(buf);
          if (ret != 0){
            *length_return = 0;
            *value_return  = NULL;
          }
          else{
            buf = XtMalloc(prop.nitems + 1);
            strncpy(buf, prop.value, prop.nitems);
            buf[prop.nitems] = '\0';
            *length_return = prop.nitems;
            *value_return  = buf;
          }
         *type_return = atom_comp_text;

    }
    else if (*target == atom_delete)
    {
      sel =(*Text_Source((Widget)src)->GetSelection)(Text_Source((Widget)src),
            &left, &right);
      if (sel)
      {
            (*Text_Source((Widget)src)->SetSelection) (Text_Source((Widget)src),
            right, right, CurrentTime);
            _XmTextDelete((XmTextWidget)src, NULL, left, right);
      }

        *value_return = NULL;
        *type_return = XmInternAtom(XtDisplay(w), "NULL", False);
        *length_return = 0;
    }
    else
    {
        _XmObjectUnlock(src);
      return False;
    }

    *format_return = 8;

    _XmObjectUnlock(src);
    return True;
}

static void
drag_transfer_proc(Widget dw, XtPointer client, Atom *selection, Atom *type,
             XtPointer value, unsigned long *length, int *format)
{
    XmTextWidget w = (XmTextWidget)client;
    Atom atom_comp_text;
    Atom atom_text;
    Atom atom_null;
    Arg args[2];

    atom_comp_text =  XmInternAtom(XtDisplay(w), _XA_COMPOUND_TEXT, False);
    atom_text = XmInternAtom(XtDisplay(w), _XA_TEXT, False);
    atom_null =  XmInternAtom(XtDisplay(w), "NULL", False);

    if (*type != atom_null && (!value || 
      (*type != atom_comp_text && *type != atom_text && *type != XA_STRING)))
    {

    DEBUGOUT(_LtDebug(__FILE__, (Widget)w, "%s\n", 
       "drag_transfer_proc: DnD Transfer Failed(Text)"));

        XtSetArg(args[0], XmNtransferStatus, XmTRANSFER_FAILURE);
        XtSetArg(args[1], XmNnumDropTransfers, 0);
        XtSetValues(dw, args, 2);

    }
    else if (*type != atom_null)
    {
      XTextProperty prop;
      int count, i;
      char **list;

      if (*type == XA_STRING){
          char *buf;

          buf = XtMalloc(*length + 1);
          strncpy(buf, (char *)value, *length);
          buf[*length] = '\0';

          /* Convert from XA_STRING to COMPOUND_TEXT */
          XmbTextListToTextProperty(XtDisplay(w), &buf, 1,
                  XCompoundTextStyle, &prop);

          XtFree(buf);
        }
        else{
            prop.value = (unsigned char *)value;
            prop.encoding = *type;
            prop.format = *format;
            prop.nitems = *length;
        }

        XmbTextPropertyToTextList(XtDisplay(w), &prop, &list, &count);

        for(i=0; i<count; i++){
          DoInsert(w, NULL, list[i], strlen(list[i]));
        }

    }

    if (value)
        XtFree((char *)value);
}


extern void
_Lttext_process_drop(Widget w, XtPointer client_data, XtPointer call_data)
{
    XmDropProcCallbackStruct *DropInfo =
        (XmDropProcCallbackStruct *) call_data;
    XmDropTransferEntryRec  entry[2];
    Atom atom_comp_text;
    Atom atom_text;
    Atom atom_null;
    Atom *export_targets;
    Atom target;
    Cardinal num_export_targets;
    Arg     args[10];
    Cardinal      n = 0;
    XmTextPosition pos;
    Boolean comp_text, text, string; 

    atom_comp_text =  XmInternAtom(XtDisplay(w), _XA_COMPOUND_TEXT, False);
    atom_text = XmInternAtom(XtDisplay(w), _XA_TEXT, False);
    atom_null = XmInternAtom(XtDisplay(w), "NULL", False);

    if ((DropInfo->dropAction == XmDROP) && 
        ((DropInfo->operation == XmDROP_COPY) ||
       (DropInfo->operation == XmDROP_MOVE)))
    {
        /* Get valid target */
        XtSetArg(args[n], XmNexportTargets, &export_targets); n++;
        XtSetArg(args[n], XmNnumExportTargets, &num_export_targets); n++;
        XtGetValues(DropInfo->dragContext, args, n);
      comp_text = text = string = False;
        for (n = 0; n < num_export_targets; n++) {
            if (export_targets[n] == atom_comp_text)
                comp_text = True;
          else if (export_targets[n] == atom_text)
                text = True;
          else if (export_targets[n] == XA_STRING)
                string = True;
        }
      if (comp_text)
          target = atom_comp_text;
      else if (text)
          target = atom_text;
      else if (string)
          target = XA_STRING;
      else
          target = atom_null;

        entry[0].target = target;
        entry[0].client_data = (XtPointer) w;

      n = 0;
      if (target == atom_null)
      {
            XtSetArg(args [n], XmNtransferStatus, XmTRANSFER_FAILURE); n++;
            XtSetArg(args [n], XmNnumDropTransfers, 0); n++;
            DropInfo->operation = XmDROP_NOOP;
            DropInfo->dropSiteStatus = XmINVALID_DROP_SITE;
      }
      else if (DropInfo->operation == XmDROP_MOVE)
      {
            entry[1].target = XmInternAtom(XtDisplay(w), _XA_DELETE, False);
            entry[1].client_data = (XtPointer) w;
            XtSetArg(args [n], XmNnumDropTransfers, 2); n++;
            DropInfo->dropSiteStatus = XmINVALID_DROP_SITE;
      }
      else
      {
            XtSetArg(args [n], XmNnumDropTransfers, 1); n++;
            DropInfo->dropSiteStatus = XmINVALID_DROP_SITE;
      }
        XtSetArg(args [n], XmNdropTransfers, entry); n++;
        XtSetArg(args [n], XmNtransferProc, drag_transfer_proc); n++;

      /* We should move cursor at this point?. */
        pos = (*Text_Output(w)->XYToPos)((XmTextWidget)w,
                              DropInfo->x, DropInfo->y);
      XmTextSetCursorPosition(w, pos);
    }
    else /* veto */
    {
        XtSetArg(args [n], XmNtransferStatus, XmTRANSFER_FAILURE); n++;
        XtSetArg(args [n], XmNnumDropTransfers, 0); n++;
        DropInfo->operation = XmDROP_NOOP;
        DropInfo->dropSiteStatus = XmINVALID_DROP_SITE;
    }

    XmDropTransferStart (DropInfo->dragContext, args, n);    

}


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

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


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

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


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

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


static void
ProcessTab(Widget w, XEvent *ev, String *params, Cardinal *num_params)
{
    DEBUGOUT(_LtDebug(__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(_LtDebug(__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(_LtDebug(__FILE__, w, "ScrollOneLineUp\n"));
    XmTextScroll(w, -1);
}


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


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


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


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


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

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



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

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

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

    /* Handle Oveflow case. (not evaluated)*/
    buf2 = XtMalloc(len+1);
    if (status == XBufferOverflow)
      XmImMbLookupString((Widget)w, (XKeyPressedEvent *)ev, buf2, len, &keysym, &status);
    else
      strncpy(buf2, buf, len);

    if (_LtDebugInDebug(__FILE__, w))
    {
      DEBUGOUT(_LtDebug(__FILE__, w, "XmImMbLookupString => %d\n", len));
      DEBUGOUT(_LtDebug0(__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(_LtDebug0(__FILE__, w, "\tKeySym 0x%X\n", keysym));
      }

      if (len > 0)
      {
          int i;

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

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

/* This is the insertion point for secondary selections */
static void
SetAnchor(Widget w, XEvent *ev, String *params, Cardinal *num_params)
{
    DEBUGOUT(_LtDebug(__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(_LtDebug(__FILE__, w, "SetCursorPosition\n"));
}

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

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


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

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


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

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

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

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

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

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

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

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

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

    DEBUGOUT(_LtDebug(__FILE__, w, "TextFocusIn\n"));

    if (Text_Editable(w))
    {
      XmImSetFocusValues(w, NULL, 0);
        _XmImSendSpot(w);
    }
#if EXTRA_FOCUS
    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;
    }
#endif
    /*
     * 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)
{
#if EXTRA_FOCUS
    XmTextVerifyCallbackStruct cbs;
    OutputData o = Text_OutputData(w);
#endif

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

    if (Text_Editable(w))
    {
      XmImUnsetFocus(w);
    }
#if EXTRA_FOCUS
    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;
    }
#endif
    /*
     * 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(_LtDebug(__FILE__, w, "UnKill\n"));
}

static void
VoidAction(Widget w, XEvent *ev, String *params, Cardinal *num_params)
{
    DEBUGOUT(_LtDebug(__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;
}


extern 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;
}

Generated by  Doxygen 1.6.0   Back to index