home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / X / mit / lib / Xaw / Text.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-07-21  |  92.3 KB  |  3,301 lines

  1. /* $XConsortium: Text.c,v 1.184 92/11/16 15:00:13 converse Exp $ */
  2.  
  3. /***********************************************************
  4. Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts,
  5. and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
  6.  
  7.                         All Rights Reserved
  8.  
  9. Permission to use, copy, modify, and distribute this software and its 
  10. documentation for any purpose and without fee is hereby granted, 
  11. provided that the above copyright notice appear in all copies and that
  12. both that copyright notice and this permission notice appear in 
  13. supporting documentation, and that the names of Digital or MIT not be
  14. used in advertising or publicity pertaining to distribution of the
  15. software without specific, written prior permission.  
  16.  
  17. DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
  18. ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
  19. DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
  20. ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  21. WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
  22. ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  23. SOFTWARE.
  24.  
  25. ******************************************************************/
  26.  
  27. #include <X11/IntrinsicP.h>
  28. #include <X11/StringDefs.h>
  29. #include <X11/Shell.h>
  30. #include <X11/Xatom.h>
  31. #include <stdio.h>
  32.  
  33. #include <X11/Xmu/Atoms.h>
  34. #include <X11/Xmu/CharSet.h>
  35. #include <X11/Xmu/Converters.h>
  36. #include <X11/Xmu/StdSel.h>
  37. #include <X11/Xmu/Misc.h>
  38.  
  39. #include <X11/Xaw/XawInit.h>
  40. #include <X11/Xaw/Cardinals.h>
  41. #include <X11/Xaw/Scrollbar.h>
  42. #include <X11/Xaw/TextP.h>
  43.  
  44. #include <X11/Xfuncs.h>
  45.  
  46. unsigned long FMT8BIT = 0L;
  47.  
  48. #define SinkClearToBG          XawTextSinkClearToBackground
  49.  
  50. #define SrcScan                XawTextSourceScan
  51. #define SrcRead                XawTextSourceRead
  52. #define SrcReplace             XawTextSourceReplace
  53. #define SrcSearch              XawTextSourceSearch
  54. #define SrcCvtSel              XawTextSourceConvertSelection
  55. #define SrcSetSelection        XawTextSourceSetSelection
  56.  
  57. #define BIGNUM ((Dimension)32023)
  58. #define MULTI_CLICK_TIME 500L
  59.  
  60. /*
  61.  * Compute a the maximum length of a cut buffer that we can pass at any
  62.  * time.  The 64 allows for the overhead of the Change Property request.
  63.  */
  64.  
  65. #define MAX_CUT_LEN(dpy)  (XMaxRequestSize(dpy) - 64)
  66.  
  67. #define IsValidLine(ctx, num) ( ((num) == 0) || \
  68.                     ((ctx)->text.lt.info[(num)].position != 0) )
  69.  
  70. /*
  71.  * Defined in Text.c
  72.  */
  73. static void UnrealizeScrollbars();
  74. static void VScroll(), VJump(), HScroll(), HJump(), ClearWindow(); 
  75. static void DisplayTextWindow(), ModifySelection(), PushCopyQueue();
  76. static void UpdateTextInLine(), UpdateTextInRectangle(), PopCopyQueue();
  77. static void FlushUpdate();
  78. static Boolean LineAndXYForPosition(), TranslateExposeRegion();
  79. static XawTextPosition FindGoodPosition(), _BuildLineTable();
  80.  
  81. void _XawTextAlterSelection(), _XawTextExecuteUpdate();
  82. void _XawTextBuildLineTable(), _XawTextSetScrollBars();
  83.  
  84. /****************************************************************
  85.  *
  86.  * Full class record constant
  87.  *
  88.  ****************************************************************/
  89.  
  90. static XawTextSelectType defaultSelectTypes[] = {
  91.   XawselectPosition, XawselectWord, XawselectLine, XawselectParagraph,
  92.   XawselectAll,      XawselectNull,
  93. };
  94.  
  95. static caddr_t defaultSelectTypesPtr = (caddr_t)defaultSelectTypes;
  96. extern char *_XawDefaultTextTranslations1, *_XawDefaultTextTranslations2,
  97.   *_XawDefaultTextTranslations3;
  98. static Dimension defWidth = 100;
  99. static Dimension defHeight = DEFAULT_TEXT_HEIGHT;
  100.  
  101. #define offset(field) XtOffsetOf(TextRec, field)
  102. static XtResource resources[] = {
  103.   {XtNwidth, XtCWidth, XtRDimension, sizeof(Dimension),
  104.      offset(core.width), XtRDimension, (XtPointer)&defWidth},
  105.   {XtNcursor, XtCCursor, XtRCursor, sizeof(Cursor),
  106.      offset(simple.cursor), XtRString, "xterm"},
  107.   {XtNheight, XtCHeight, XtRDimension, sizeof(Dimension),
  108.      offset(core.height), XtRDimension, (XtPointer)&defHeight},
  109.   {XtNdisplayPosition, XtCTextPosition, XtRInt, sizeof(XawTextPosition), 
  110.      offset(text.lt.top), XtRImmediate, (XtPointer)0},
  111.   {XtNinsertPosition, XtCTextPosition, XtRInt, sizeof(XawTextPosition),
  112.      offset(text.insertPos), XtRImmediate,(XtPointer)0},
  113.   {XtNleftMargin, XtCMargin, XtRPosition, sizeof (Position),
  114.      offset(text.r_margin.left), XtRImmediate, (XtPointer)2},
  115.   {XtNrightMargin, XtCMargin, XtRPosition, sizeof (Position),
  116.      offset(text.r_margin.right), XtRImmediate, (XtPointer)4},
  117.   {XtNtopMargin, XtCMargin, XtRPosition, sizeof (Position),
  118.      offset(text.r_margin.top), XtRImmediate, (XtPointer)2},
  119.   {XtNbottomMargin, XtCMargin, XtRPosition, sizeof (Position),
  120.      offset(text.r_margin.bottom), XtRImmediate, (XtPointer)2},
  121.   {XtNselectTypes, XtCSelectTypes, XtRPointer,
  122.      sizeof(XawTextSelectType*), offset(text.sarray),
  123.      XtRPointer, (XtPointer)&defaultSelectTypesPtr},
  124.   {XtNtextSource, XtCTextSource, XtRWidget, sizeof (Widget),
  125.      offset(text.source), XtRImmediate, NULL},
  126.   {XtNtextSink, XtCTextSink, XtRWidget, sizeof (Widget),
  127.      offset(text.sink), XtRImmediate, NULL},
  128.   {XtNdisplayCaret, XtCOutput, XtRBoolean, sizeof(Boolean),
  129.      offset(text.display_caret), XtRImmediate, (XtPointer)True},
  130.   {XtNscrollVertical, XtCScroll, XtRScrollMode, sizeof(XawTextScrollMode),
  131.      offset(text.scroll_vert), XtRImmediate, (XtPointer) XawtextScrollNever},
  132.   {XtNscrollHorizontal, XtCScroll, XtRScrollMode, sizeof(XawTextScrollMode),
  133.      offset(text.scroll_horiz), XtRImmediate, (XtPointer) XawtextScrollNever},
  134.   {XtNwrap, XtCWrap, XtRWrapMode, sizeof(XawTextWrapMode),
  135.      offset(text.wrap), XtRImmediate, (XtPointer) XawtextWrapNever},
  136.   {XtNresize, XtCResize, XtRResizeMode, sizeof(XawTextResizeMode),
  137.      offset(text.resize), XtRImmediate, (XtPointer) XawtextResizeNever},
  138.   {XtNautoFill, XtCAutoFill, XtRBoolean, sizeof(Boolean),
  139.      offset(text.auto_fill), XtRImmediate, (XtPointer) FALSE},
  140.   {XtNunrealizeCallback, XtCCallback, XtRCallback, sizeof(XtPointer),
  141.      offset(text.unrealize_callbacks), XtRCallback, (XtPointer) NULL}
  142. };
  143. #undef offset
  144.  
  145. #define done(address, type) \
  146.         { toVal->size = sizeof(type); toVal->addr = (caddr_t) address; }
  147.  
  148.  
  149.  
  150. /* ARGSUSED */
  151. static void 
  152. CvtStringToScrollMode(args, num_args, fromVal, toVal)
  153. XrmValuePtr args;        /* unused */
  154. Cardinal    *num_args;    /* unused */
  155. XrmValuePtr    fromVal;
  156. XrmValuePtr    toVal;
  157. {
  158.   static XawTextScrollMode scrollMode;
  159.   static  XrmQuark  QScrollNever, QScrollAlways, QScrollWhenNeeded;
  160.   XrmQuark    q;
  161.   char        lowerName[BUFSIZ];
  162.   static Boolean inited = FALSE;
  163.     
  164.   if ( !inited ) {
  165.     QScrollNever      = XrmPermStringToQuark(XtEtextScrollNever);
  166.     QScrollWhenNeeded = XrmPermStringToQuark(XtEtextScrollWhenNeeded);
  167.     QScrollAlways     = XrmPermStringToQuark(XtEtextScrollAlways);
  168.     inited = TRUE;
  169.   }
  170.  
  171.   XmuCopyISOLatin1Lowered (lowerName, (char *)fromVal->addr);
  172.   q = XrmStringToQuark(lowerName);
  173.  
  174.   if      (q == QScrollNever)          scrollMode = XawtextScrollNever;
  175.   else if (q == QScrollWhenNeeded)     scrollMode = XawtextScrollWhenNeeded;
  176.   else if (q == QScrollAlways)         scrollMode = XawtextScrollAlways;
  177.   else {
  178.     done(NULL, 0);
  179.     return;
  180.   }
  181.   done(&scrollMode, XawTextScrollMode);
  182.   return;
  183. }
  184.  
  185. /* ARGSUSED */
  186. static void 
  187. CvtStringToWrapMode(args, num_args, fromVal, toVal)
  188. XrmValuePtr args;        /* unused */
  189. Cardinal    *num_args;    /* unused */
  190. XrmValuePtr    fromVal;
  191. XrmValuePtr    toVal;
  192. {
  193.   static XawTextWrapMode wrapMode;
  194.   static  XrmQuark QWrapNever, QWrapLine, QWrapWord;
  195.   XrmQuark    q;
  196.   char        lowerName[BUFSIZ];
  197.   static Boolean inited = FALSE;
  198.     
  199.   if ( !inited ) {
  200.     QWrapNever = XrmPermStringToQuark(XtEtextWrapNever);
  201.     QWrapLine  = XrmPermStringToQuark(XtEtextWrapLine);
  202.     QWrapWord  = XrmPermStringToQuark(XtEtextWrapWord);
  203.     inited = TRUE;
  204.   }
  205.  
  206.   XmuCopyISOLatin1Lowered (lowerName, (char *)fromVal->addr);
  207.   q = XrmStringToQuark(lowerName);
  208.  
  209.   if      (q == QWrapNever)     wrapMode = XawtextWrapNever;
  210.   else if (q == QWrapLine)      wrapMode = XawtextWrapLine;
  211.   else if (q == QWrapWord)      wrapMode = XawtextWrapWord;
  212.   else {
  213.     done(NULL, 0);
  214.     return;
  215.   }
  216.   done(&wrapMode, XawTextWrapMode);
  217.   return;
  218. }
  219.  
  220. /* ARGSUSED */
  221. static void 
  222. CvtStringToResizeMode(args, num_args, fromVal, toVal)
  223. XrmValuePtr args;        /* unused */
  224. Cardinal    *num_args;    /* unused */
  225. XrmValuePtr    fromVal;
  226. XrmValuePtr    toVal;
  227. {
  228.   static XawTextResizeMode resizeMode;
  229.   static  XrmQuark  QResizeNever, QResizeWidth, QResizeHeight, QResizeBoth;
  230.   XrmQuark    q;
  231.   char        lowerName[BUFSIZ];
  232.   static Boolean inited = FALSE;
  233.     
  234.   if ( !inited ) {
  235.     QResizeNever      = XrmPermStringToQuark(XtEtextResizeNever);
  236.     QResizeWidth      = XrmPermStringToQuark(XtEtextResizeWidth);
  237.     QResizeHeight     = XrmPermStringToQuark(XtEtextResizeHeight);
  238.     QResizeBoth       = XrmPermStringToQuark(XtEtextResizeBoth);
  239.     inited = TRUE;
  240.   }
  241.  
  242.   XmuCopyISOLatin1Lowered (lowerName, (char *)fromVal->addr);
  243.   q = XrmStringToQuark(lowerName);
  244.  
  245.   if      (q == QResizeNever)          resizeMode = XawtextResizeNever;
  246.   else if (q == QResizeWidth)          resizeMode = XawtextResizeWidth;
  247.   else if (q == QResizeHeight)         resizeMode = XawtextResizeHeight;
  248.   else if (q == QResizeBoth)           resizeMode = XawtextResizeBoth;
  249.   else {
  250.     done(NULL, 0);
  251.     return;
  252.   }
  253.   done(&resizeMode, XawTextResizeMode);
  254.   return;
  255. }
  256.  
  257. #undef done
  258.  
  259. static void 
  260. ClassInitialize()
  261. {
  262.   int len1 = strlen (_XawDefaultTextTranslations1);
  263.   int len2 = strlen (_XawDefaultTextTranslations2);
  264.   int len3 = strlen (_XawDefaultTextTranslations3);
  265.   char *buf = XtMalloc (len1 + len2 + len3 + 1);
  266.   char *cp = buf;
  267.  
  268.   if (!FMT8BIT)
  269.     FMT8BIT = XrmPermStringToQuark("FMT8BIT");
  270.  
  271.   XawInitializeWidgetSet();
  272.  
  273. /* 
  274.  * Set the number of actions.
  275.  */
  276.  
  277.   textClassRec.core_class.num_actions = _XawTextActionsTableCount;
  278.   
  279.   strcpy (cp, _XawDefaultTextTranslations1); cp += len1;
  280.   strcpy (cp, _XawDefaultTextTranslations2); cp += len2;
  281.   strcpy (cp, _XawDefaultTextTranslations3);
  282.   textWidgetClass->core_class.tm_table = buf;
  283.  
  284.   XtAddConverter(XtRString, XtRScrollMode, CvtStringToScrollMode, NULL, 0);
  285.   XtAddConverter(XtRString, XtRWrapMode,   CvtStringToWrapMode,   NULL, 0);
  286.   XtAddConverter(XtRString, XtRResizeMode, CvtStringToResizeMode, NULL, 0);
  287. }
  288.  
  289. /*    Function Name: PositionHScrollBar.
  290.  *    Description: Positions the Horizontal scrollbar.
  291.  *    Arguments: ctx - the text widget.
  292.  *    Returns: none
  293.  */
  294.  
  295. static void
  296. PositionHScrollBar(ctx)
  297. TextWidget ctx;
  298. {
  299.   Widget vbar = ctx->text.vbar, hbar = ctx->text.hbar;
  300.   Position top, left = 0;
  301.  
  302.   if (ctx->text.hbar == NULL) return;
  303.  
  304.   if (vbar != NULL)
  305.     left += (Position) (vbar->core.width + vbar->core.border_width);
  306.  
  307.   XtResizeWidget( hbar, ctx->core.width - left, hbar->core.height,
  308.          hbar->core.border_width );
  309.  
  310.   left -= (Position) hbar->core.border_width;
  311.   
  312.   top = ctx->core.height - ( hbar->core.height + hbar->core.border_width);
  313.   XtMoveWidget( hbar, left, top); 
  314. }
  315.  
  316. /*    Function Name: PositionVScrollBar.
  317.  *    Description: Positions the Vertical scrollbar.
  318.  *    Arguments: ctx - the text widget.
  319.  *    Returns: none.
  320.  */
  321.  
  322. static void
  323. PositionVScrollBar(ctx)
  324. TextWidget ctx;
  325. {
  326.   Widget vbar = ctx->text.vbar;
  327.   Dimension bw;
  328.  
  329.   if (vbar == NULL) return;
  330.   bw = vbar->core.border_width;
  331.  
  332.   XtResizeWidget( vbar, vbar->core.width, ctx->core.height, bw);
  333.   XtMoveWidget( vbar, -(Position)bw, -(Position)bw );
  334. }
  335.  
  336. static void 
  337. CreateVScrollBar(ctx)
  338. TextWidget ctx;
  339. {
  340.   Widget vbar;
  341.  
  342.   if (ctx->text.vbar != NULL) return;
  343.  
  344.   ctx->text.vbar = vbar =
  345.     XtCreateWidget("vScrollbar", scrollbarWidgetClass, (Widget)ctx, NULL, ZERO);
  346.   XtAddCallback( vbar, XtNscrollProc, VScroll, (XtPointer)ctx );
  347.   XtAddCallback( vbar, XtNjumpProc, VJump, (XtPointer)ctx );
  348.   if (ctx->text.hbar == NULL)
  349.       XtAddCallback((Widget) ctx, XtNunrealizeCallback, UnrealizeScrollbars,
  350.             (XtPointer) NULL);
  351.  
  352.   ctx->text.r_margin.left += vbar->core.width + vbar->core.border_width;
  353.   ctx->text.margin.left = ctx->text.r_margin.left;
  354.  
  355.   PositionVScrollBar(ctx);
  356.   PositionHScrollBar(ctx);    /* May modify location of Horiz. Bar. */
  357.  
  358.   if (XtIsRealized((Widget)ctx)) {
  359.     XtRealizeWidget(vbar);
  360.     XtMapWidget(vbar);
  361.   }
  362. }
  363.  
  364. /*    Function Name: DestroyVScrollBar
  365.  *    Description: Removes a vertical ScrollBar.
  366.  *    Arguments: ctx - the parent text widget.
  367.  *    Returns: none.
  368.  */
  369.  
  370. static void
  371. DestroyVScrollBar(ctx)
  372. TextWidget ctx;
  373. {
  374.   Widget vbar = ctx->text.vbar;
  375.  
  376.   if (vbar == NULL) return;
  377.  
  378.   ctx->text.r_margin.left -= vbar->core.width + vbar->core.border_width;
  379.   ctx->text.margin.left = ctx->text.r_margin.left;
  380.   if (ctx->text.hbar == NULL)
  381.       XtRemoveCallback((Widget) ctx, XtNunrealizeCallback, UnrealizeScrollbars,
  382.                (XtPointer) NULL);
  383.   XtDestroyWidget(vbar);
  384.   ctx->text.vbar = NULL;
  385.   PositionHScrollBar(ctx);
  386. }
  387.   
  388. static void 
  389. CreateHScrollBar(ctx)
  390. TextWidget ctx;
  391. {
  392.   Arg args[1];
  393.   Widget hbar;
  394.  
  395.   if (ctx->text.hbar != NULL) return;
  396.  
  397.   XtSetArg(args[0], XtNorientation, XtorientHorizontal);
  398.   ctx->text.hbar = hbar =
  399.     XtCreateWidget("hScrollbar", scrollbarWidgetClass, (Widget)ctx, args, ONE);
  400.   XtAddCallback( hbar, XtNscrollProc, HScroll, (XtPointer)ctx );
  401.   XtAddCallback( hbar, XtNjumpProc, HJump, (XtPointer)ctx );
  402.   if (ctx->text.vbar == NULL)
  403.       XtAddCallback((Widget) ctx, XtNunrealizeCallback, UnrealizeScrollbars,
  404.             (XtPointer) NULL);
  405.  
  406.   PositionHScrollBar(ctx);
  407.   if (XtIsRealized((Widget)ctx)) {
  408.     XtRealizeWidget(hbar);
  409.     XtMapWidget(hbar);
  410.   }
  411. }
  412.  
  413. /*    Function Name: DestroyHScrollBar
  414.  *    Description: Removes a horizontal ScrollBar.
  415.  *    Arguments: ctx - the parent text widget.
  416.  *    Returns: none.
  417.  */
  418.  
  419. static void
  420. DestroyHScrollBar(ctx)
  421. TextWidget ctx;
  422. {
  423.   Widget hbar = ctx->text.hbar;
  424.  
  425.   if (hbar == NULL) return;
  426.  
  427. /*
  428.   ctx->text.r_margin.bottom -= hbar->core.height + hbar->core.border_width;
  429.   ctx->text.margin.bottom = ctx->text.r_margin.bottom;
  430. */
  431.   if (ctx->text.vbar == NULL)
  432.       XtRemoveCallback((Widget) ctx, XtNunrealizeCallback, UnrealizeScrollbars,
  433.                (XtPointer) NULL);
  434.   XtDestroyWidget(hbar);
  435.   ctx->text.hbar = NULL;
  436. }
  437.  
  438. /* ARGSUSED */
  439. static void 
  440. Initialize(request, new, args, num_args)
  441. Widget request, new;
  442. ArgList args;            /* unused */
  443. Cardinal *num_args;        /* unused */
  444. {
  445.   TextWidget ctx = (TextWidget) new;
  446.   char error_buf[BUFSIZ];
  447.  
  448.   ctx->text.lt.lines = 0;
  449.   ctx->text.lt.info = NULL;
  450.   bzero((char *) &(ctx->text.origSel), sizeof(XawTextSelection));
  451.   bzero((char *) &(ctx->text.s), sizeof(XawTextSelection)); 
  452.   ctx->text.s.type = XawselectPosition;
  453.   ctx->text.salt = NULL;
  454.   ctx->text.hbar = ctx->text.vbar = (Widget) NULL;
  455.   ctx->text.lasttime = 0; /* ||| correct? */
  456.   ctx->text.time = 0; /* ||| correct? */
  457.   ctx->text.showposition = TRUE;
  458.   ctx->text.lastPos = (ctx->text.source != NULL) ? GETLASTPOS : 0;
  459.   ctx->text.file_insert = NULL;
  460.   ctx->text.search = NULL;
  461.   ctx->text.updateFrom = (XawTextPosition *) XtMalloc(ONE);
  462.   ctx->text.updateTo = (XawTextPosition *) XtMalloc(ONE);
  463.   ctx->text.numranges = ctx->text.maxranges = 0;
  464.   ctx->text.gc = DefaultGCOfScreen(XtScreen(ctx)); 
  465.   ctx->text.hasfocus = FALSE;
  466.   ctx->text.margin = ctx->text.r_margin; /* Strucure copy. */
  467.   ctx->text.update_disabled = FALSE;
  468.   ctx->text.old_insert = -1;
  469.   ctx->text.mult = 1;
  470.   ctx->text.single_char = FALSE;
  471.   ctx->text.copy_area_offsets = NULL;
  472.  
  473.   if (ctx->core.height == DEFAULT_TEXT_HEIGHT) {
  474.     ctx->core.height = VMargins(ctx);
  475.     if (ctx->text.sink != NULL)
  476.       ctx->core.height += XawTextSinkMaxHeight(ctx->text.sink, 1);
  477.   }
  478.  
  479.   if (ctx->text.scroll_vert != XawtextScrollNever) 
  480.     if ( (ctx->text.resize == XawtextResizeHeight) ||
  481.           (ctx->text.resize == XawtextResizeBoth) ) {
  482.       sprintf(error_buf, "Text Widget (%s):\n %s %s.", ctx->core.name,
  483.           "Vertical scrolling not allowed with height resize.\n",
  484.           "Vertical scrolling has been DEACTIVATED.");
  485.       XtAppWarning(XtWidgetToApplicationContext(new), error_buf);
  486.       ctx->text.scroll_vert = XawtextScrollNever;
  487.     }
  488.     else if (ctx->text.scroll_vert == XawtextScrollAlways)
  489.       CreateVScrollBar(ctx);
  490.  
  491.   if (ctx->text.scroll_horiz != XawtextScrollNever) 
  492.     if (ctx->text.wrap != XawtextWrapNever) {
  493.       sprintf(error_buf, "Text Widget (%s):\n %s %s.", ctx->core.name,
  494.           "Horizontal scrolling not allowed with wrapping active.\n",
  495.           "Horizontal scrolling has been DEACTIVATED.");
  496.       XtAppWarning(XtWidgetToApplicationContext(new), error_buf);
  497.       ctx->text.scroll_horiz = XawtextScrollNever;
  498.     }
  499.     else if ( (ctx->text.resize == XawtextResizeWidth) ||
  500.           (ctx->text.resize == XawtextResizeBoth) ) {
  501.       sprintf(error_buf, "Text Widget (%s):\n %s %s.", ctx->core.name,
  502.           "Horizontal scrolling not allowed with width resize.\n",
  503.           "Horizontal scrolling has been DEACTIVATED.");
  504.       XtAppWarning(XtWidgetToApplicationContext(new), error_buf);
  505.       ctx->text.scroll_horiz = XawtextScrollNever;
  506.     }
  507.     else if (ctx->text.scroll_horiz == XawtextScrollAlways)
  508.       CreateHScrollBar(ctx);
  509. }
  510.  
  511. static void 
  512. Realize( w, valueMask, attributes )
  513. Widget w;
  514. Mask *valueMask;
  515. XSetWindowAttributes *attributes;
  516. {
  517.   TextWidget ctx = (TextWidget)w;
  518.   void _XawTextCheckResize();
  519.  
  520.   (*textClassRec.core_class.superclass->core_class.realize)
  521.     (w, valueMask, attributes);
  522.   
  523.   if (ctx->text.hbar != NULL) {            /* Put up Hbar -- Must be first. */
  524.     XtRealizeWidget(ctx->text.hbar);
  525.     XtMapWidget(ctx->text.hbar);
  526.   }
  527.  
  528.   if (ctx->text.vbar != NULL) {            /* Put up Vbar. */
  529.     XtRealizeWidget(ctx->text.vbar);
  530.     XtMapWidget(ctx->text.vbar);
  531.   }
  532.  
  533.   _XawTextBuildLineTable(ctx, ctx->text.lt.top, TRUE);
  534.   _XawTextSetScrollBars(ctx);
  535.   _XawTextCheckResize(ctx);
  536. }
  537.  
  538. /*ARGSUSED*/
  539. static void UnrealizeScrollbars(widget, client, call)
  540. Widget        widget;        /* Text widget */
  541. XtPointer    client;        /* unused */
  542. XtPointer    call;         /* unused */
  543. {
  544.     TextWidget ctx = (TextWidget) widget;
  545.     
  546.     if (ctx->text.hbar)
  547.     XtUnrealizeWidget(ctx->text.hbar);
  548.     if (ctx->text.vbar)
  549.     XtUnrealizeWidget(ctx->text.vbar);
  550. }
  551.  
  552. /* Utility routines for support of Text */
  553.  
  554. static void
  555. _CreateCutBuffers(d)
  556. Display *d;
  557. {
  558.   static struct _DisplayRec {
  559.     struct _DisplayRec *next;
  560.     Display *dpy;
  561.   } *dpy_list = NULL;
  562.   struct _DisplayRec *dpy_ptr;
  563.  
  564.   for (dpy_ptr = dpy_list; dpy_ptr != NULL; dpy_ptr = dpy_ptr->next)
  565.     if (dpy_ptr->dpy == d) return;
  566.  
  567.   dpy_ptr = XtNew(struct _DisplayRec);
  568.   dpy_ptr->next = dpy_list;
  569.   dpy_ptr->dpy = d;
  570.   dpy_list = dpy_ptr;
  571.  
  572. #define Create(buffer) \
  573.     XChangeProperty(d, RootWindow(d, 0), buffer, XA_STRING, 8, \
  574.             PropModeAppend, NULL, 0 );
  575.  
  576.     Create( XA_CUT_BUFFER0 );
  577.     Create( XA_CUT_BUFFER1 );
  578.     Create( XA_CUT_BUFFER2 );
  579.     Create( XA_CUT_BUFFER3 );
  580.     Create( XA_CUT_BUFFER4 );
  581.     Create( XA_CUT_BUFFER5 );
  582.     Create( XA_CUT_BUFFER6 );
  583.     Create( XA_CUT_BUFFER7 );
  584.  
  585. #undef Create
  586. }
  587.  
  588. /*
  589.  * Procedure to manage insert cursor visibility for editable text.  It uses
  590.  * the value of ctx->insertPos and an implicit argument. In the event that
  591.  * position is immediately preceded by an eol graphic, then the insert cursor
  592.  * is displayed at the beginning of the next line.
  593. */
  594. static void 
  595. InsertCursor (w, state)
  596. Widget w;
  597. XawTextInsertState state;
  598. {
  599.   TextWidget ctx = (TextWidget)w;
  600.   Position x, y;
  601.   int line;
  602.   
  603.   if (ctx->text.lt.lines < 1) return;
  604.  
  605.   if ( LineAndXYForPosition(ctx, ctx->text.insertPos, &line, &x, &y) ) {
  606.     if (line < ctx->text.lt.lines)
  607.       y += (ctx->text.lt.info[line + 1].y - ctx->text.lt.info[line].y) + 1;
  608.     else
  609.       y += (ctx->text.lt.info[line].y - ctx->text.lt.info[line - 1].y) + 1;
  610.  
  611.     if (ctx->text.display_caret)
  612.       XawTextSinkInsertCursor(ctx->text.sink, x, y, state);
  613.   }
  614.   ctx->text.ev_x = x;
  615.   ctx->text.ev_y = y;
  616. }
  617.  
  618. /*
  619.  * Procedure to register a span of text that is no longer valid on the display
  620.  * It is used to avoid a number of small, and potentially overlapping, screen
  621.  * updates. 
  622. */
  623.  
  624. void
  625. _XawTextNeedsUpdating(ctx, left, right)
  626. TextWidget ctx;
  627. XawTextPosition left, right;
  628. {
  629.   int i;
  630.   if (left < right) {
  631.     for (i = 0; i < ctx->text.numranges; i++) {
  632.       if (left <= ctx->text.updateTo[i] && right >= ctx->text.updateFrom[i]) {
  633.     ctx->text.updateFrom[i] = Min(left, ctx->text.updateFrom[i]);
  634.     ctx->text.updateTo[i] = Max(right, ctx->text.updateTo[i]);
  635.     return;
  636.       }
  637.     }
  638.     ctx->text.numranges++;
  639.     if (ctx->text.numranges > ctx->text.maxranges) {
  640.       ctx->text.maxranges = ctx->text.numranges;
  641.       i = ctx->text.maxranges * sizeof(XawTextPosition);
  642.       ctx->text.updateFrom = (XawTextPosition *) 
  643.     XtRealloc((char *)ctx->text.updateFrom, (unsigned) i);
  644.       ctx->text.updateTo = (XawTextPosition *) 
  645.     XtRealloc((char *)ctx->text.updateTo, (unsigned) i);
  646.     }
  647.     ctx->text.updateFrom[ctx->text.numranges - 1] = left;
  648.     ctx->text.updateTo[ctx->text.numranges - 1] = right;
  649.   }
  650. }
  651.  
  652. /*
  653.  * Procedure to read a span of text in Ascii form. This is purely a hack and
  654.  * we probably need to add a function to sources to provide this functionality.
  655.  * [note: this is really a private procedure but is used in multiple modules].
  656.  */
  657.  
  658. char *
  659. _XawTextGetText(ctx, left, right)
  660. TextWidget ctx;
  661. XawTextPosition left, right;
  662. {
  663.   char *result, *tempResult;
  664.   XawTextBlock text;
  665.  
  666.   tempResult = result = XtMalloc(((Cardinal)(right - left)) + ONE);
  667.   while (left < right) {
  668.     left = SrcRead(ctx->text.source, left, &text, right - left);
  669.     if (!text.length)
  670.     break;
  671.     (void) strncpy(tempResult, text.ptr, text.length);
  672.     tempResult += text.length;
  673.   }
  674.   *tempResult = '\0';
  675.   return(result);
  676. }
  677.  
  678. /* like _XawTextGetText, but enforces ICCCM STRING type encoding */
  679.  
  680. char *
  681. _XawTextGetSTRING(ctx, left, right)
  682. TextWidget ctx;
  683. XawTextPosition left, right;
  684. {
  685.   register unsigned char *s;
  686.   register unsigned char c;
  687.   register long i, j, n;
  688.  
  689.   s = (unsigned char *)_XawTextGetText(ctx, left, right);
  690.   /* only HT and NL control chars are allowed, strip out others */
  691.   n = strlen((char *)s);
  692.   i = 0;
  693.   for (j = 0; j < n; j++) {
  694.     c = s[j];
  695.     if (((c >= 0x20) && c <= 0x7f) ||
  696.     (c >= 0xa0) || (c == '\t') || (c == '\n')) {
  697.       s[i] = c;
  698.       i++;
  699.     }
  700.   }
  701.   s[i] = 0;
  702.   return (char *)s;
  703. }
  704.  
  705. /* 
  706.  * This routine maps an x and y position in a window that is displaying text
  707.  * into the corresponding position in the source.
  708.  *
  709.  * NOTE: it is illegal to call this routine unless there is a valid line table!
  710.  */
  711.  
  712. /*** figure out what line it is on ***/
  713.  
  714. static XawTextPosition
  715. PositionForXY (ctx, x, y)
  716. TextWidget ctx;
  717. Position x,y;
  718. {
  719.   int fromx, line, width, height;
  720.   XawTextPosition position;
  721.  
  722.   if (ctx->text.lt.lines == 0) return 0;
  723.   
  724.   for (line = 0; line < ctx->text.lt.lines - 1; line++) {
  725.     if (y <= ctx->text.lt.info[line + 1].y)
  726.       break;
  727.   }
  728.   position = ctx->text.lt.info[line].position;
  729.   if (position >= ctx->text.lastPos)
  730.     return(ctx->text.lastPos);
  731.   fromx = (int) ctx->text.margin.left; 
  732.   XawTextSinkFindPosition( ctx->text.sink, position, fromx, x - fromx,
  733.               FALSE, &position, &width, &height);
  734.   if (position >= ctx->text.lt.info[line + 1].position)
  735.     position = SrcScan(ctx->text.source, ctx->text.lt.info[line + 1].position,
  736.                XawstPositions, XawsdLeft, 1, TRUE);
  737.   if (position > ctx->text.lastPos) position = ctx->text.lastPos;
  738.   return(position);
  739. }
  740.  
  741. /*
  742.  * This routine maps a source position in to the corresponding line number
  743.  * of the text that is displayed in the window.
  744.  *
  745.  * NOTE: It is illegal to call this routine unless there is a valid line table!
  746.  */
  747.  
  748. static int 
  749. LineForPosition (ctx, position)
  750. TextWidget ctx;
  751. XawTextPosition position;
  752. {
  753.   int line;
  754.   
  755.   for (line = 0; line < ctx->text.lt.lines; line++)
  756.     if (position < ctx->text.lt.info[line + 1].position)
  757.       break;
  758.   return(line);
  759. }
  760.  
  761. /*
  762.  * This routine maps a source position into the corresponding line number
  763.  * and the x, y coordinates of the text that is displayed in the window.
  764.  *
  765.  * NOTE: It is illegal to call this routine unless there is a valid line table!
  766.  */
  767.  
  768. static Boolean
  769. LineAndXYForPosition (ctx, pos, line, x, y)
  770. TextWidget ctx;
  771. XawTextPosition pos;
  772. int *line;
  773. Position *x, *y;
  774. {
  775.   XawTextPosition linePos, endPos;
  776.   Boolean visible;
  777.   int realW, realH;
  778.  
  779.   *line = 0;
  780.   *x = ctx->text.margin.left;
  781.   *y = ctx->text.margin.top;
  782.   if (visible = IsPositionVisible(ctx, pos)) {
  783.     *line = LineForPosition(ctx, pos);
  784.     *y = ctx->text.lt.info[*line].y;
  785.     *x = ctx->text.margin.left;
  786.     linePos = ctx->text.lt.info[*line].position;
  787.     XawTextSinkFindDistance( ctx->text.sink, linePos,
  788.                 *x, pos, &realW, &endPos, &realH);
  789.     *x += realW;
  790.   }
  791.   return(visible);
  792. }
  793.  
  794. /*
  795.  * This routine builds a line table. It does this by starting at the
  796.  * specified position and measuring text to determine the staring position
  797.  * of each line to be displayed. It also determines and saves in the
  798.  * linetable all the required metrics for displaying a given line (e.g.
  799.  * x offset, y offset, line length, etc.).
  800.  */
  801.  
  802. void 
  803. _XawTextBuildLineTable (ctx, position, force_rebuild)
  804. TextWidget ctx;
  805. XawTextPosition position;    /* top. */
  806. Boolean force_rebuild;
  807. {
  808.   Dimension height = 0;
  809.   int lines = 0; 
  810.   Cardinal size;
  811.  
  812.   if ((int)ctx->core.height > VMargins(ctx)) {
  813.     height = ctx->core.height - VMargins(ctx);
  814.     lines = XawTextSinkMaxLines(ctx->text.sink, height);
  815.   }
  816.   size = sizeof(XawTextLineTableEntry) * (lines + 1);
  817.  
  818.   if ( (lines != ctx->text.lt.lines) || (ctx->text.lt.info == NULL) ) {
  819.     ctx->text.lt.info = (XawTextLineTableEntry *) XtRealloc((char *) ctx->text.
  820.                                 lt.info, size);
  821.     ctx->text.lt.lines = lines;
  822.     force_rebuild = TRUE;
  823.   }
  824.  
  825.   if ( force_rebuild || (position != ctx->text.lt.top) ) {
  826.     bzero((char *) ctx->text.lt.info, size);
  827.     (void) _BuildLineTable(ctx, ctx->text.lt.top = position, zeroPosition, 0);
  828.   }
  829. }
  830.  
  831. /*
  832.  * This assumes that the line table does not change size.
  833.  */
  834.  
  835. static XawTextPosition
  836. _BuildLineTable(ctx, position, min_pos, line)
  837. TextWidget ctx;
  838. XawTextPosition position, min_pos;    
  839. int line;
  840. {
  841.   XawTextLineTableEntry * lt = ctx->text.lt.info + line;
  842.   XawTextPosition endPos;
  843.   Position y;
  844.   int count, width, realW, realH;
  845.   Widget src = ctx->text.source;
  846.  
  847.   if ( ((ctx->text.resize == XawtextResizeWidth) ||
  848.     (ctx->text.resize == XawtextResizeBoth)    ) ||
  849.        (ctx->text.wrap == XawtextWrapNever) )
  850.     width = BIGNUM;
  851.   else 
  852.     width = Max(0, ((int)ctx->core.width - (int)HMargins(ctx)));
  853.  
  854.   y = ( (line == 0) ? ctx->text.margin.top : lt->y );
  855.  
  856.   while ( TRUE ) {
  857.     lt->y = y;
  858.     lt->position = position;
  859.     
  860.     XawTextSinkFindPosition( ctx->text.sink, position, ctx->text.margin.left,
  861.                 width, ctx->text.wrap == XawtextWrapWord,
  862.                 &endPos, &realW, &realH);
  863.     lt->textWidth = realW;
  864.     y += realH;
  865.  
  866.     if (ctx->text.wrap == XawtextWrapNever) 
  867.       endPos = SrcScan(src, position, XawstEOL, XawsdRight, 1, TRUE);
  868.  
  869.     if ( endPos == ctx->text.lastPos) { /* We have reached the end. */
  870.       if(SrcScan(src, position, XawstEOL, XawsdRight, 1, FALSE) == endPos)
  871.     break;
  872.     }
  873.  
  874.     ++lt;
  875.     ++line;
  876.     if ( (line > ctx->text.lt.lines) ||
  877.      ((lt->position == (position = endPos)) && (position > min_pos)) )
  878.       return(position);
  879.   }
  880.  
  881. /*
  882.  * If we are at the end of the buffer put two special lines in the table.
  883.  *
  884.  * a) Both have position > text.lastPos and lt->textWidth = 0.
  885.  * b) The first has a real height, and the second has a height that
  886.  *    is the rest of the screen.
  887.  *
  888.  * I counld fill in the rest of the table with valid heights and a large
  889.  * lastPos, but this method keeps the number of fill regions down to a 
  890.  * minimum.
  891.  *
  892.  * One valid endty is needed at the end of the table so that the cursor
  893.  * does not jump off the bottom of the window.
  894.  */
  895.  
  896.   for ( count = 0; count < 2 ; count++) 
  897.     if (line++ < ctx->text.lt.lines) { /* make sure not to run of the end. */
  898.       (++lt)->y = (count == 0) ? y : ctx->core.height;
  899.       lt->textWidth = 0;
  900.       lt->position = ctx->text.lastPos + 100;
  901.     }
  902.  
  903.   if (line < ctx->text.lt.lines) /* Clear out rest of table. */
  904.     bzero( (char *) (lt + 1), 
  905.       (ctx->text.lt.lines - line) * sizeof(XawTextLineTableEntry) );
  906.  
  907.   ctx->text.lt.info[ctx->text.lt.lines].position = lt->position;
  908.  
  909.   return(endPos);
  910. }
  911.  
  912. /*    Function Name: GetWidestLine
  913.  *    Description: Returns the width (in pixels) of the widest line that
  914.  *                   is currently visable.
  915.  *    Arguments: ctx - the text widget.
  916.  *    Returns: the width of the widest line.
  917.  *
  918.  * NOTE: This function requires a valid line table.
  919.  */
  920.  
  921. static Dimension
  922. GetWidestLine(ctx)
  923. TextWidget ctx;
  924. {
  925.   int i;
  926.   Dimension widest;
  927.   XawTextLineTablePtr lt = &(ctx->text.lt);
  928.  
  929.   for (i = 0, widest = 1 ; i < lt->lines ; i++)
  930.     if (widest < lt->info[i].textWidth)
  931.       widest = lt->info[i].textWidth;
  932.   
  933.   return(widest);
  934. }
  935.  
  936. static void
  937. CheckVBarScrolling(ctx)
  938. TextWidget ctx;
  939. {
  940.   float first, last;
  941.   Boolean temp = (ctx->text.vbar == NULL);
  942.  
  943.   if (ctx->text.scroll_vert == XawtextScrollNever) return;
  944.  
  945.   if ( (ctx->text.lastPos > 0) && (ctx->text.lt.lines > 0)) {
  946.     first = ctx->text.lt.top;
  947.     first /= (float) ctx->text.lastPos;
  948.     last = ctx->text.lt.info[ctx->text.lt.lines].position;
  949.     if ( ctx->text.lt.info[ctx->text.lt.lines].position < ctx->text.lastPos )
  950.       last /= (float) ctx->text.lastPos;
  951.     else 
  952.       last = 1.0;
  953.  
  954.     if (ctx->text.scroll_vert == XawtextScrollWhenNeeded) {
  955.       int line;
  956.       XawTextPosition last_pos;
  957.       Position y = ctx->core.height - ctx->text.margin.bottom;    
  958.  
  959.       if (ctx->text.hbar != NULL)
  960.     y -= (ctx->text.hbar->core.height +
  961.           2 * ctx->text.hbar->core.border_width);
  962.  
  963.       last_pos = PositionForXY(ctx, (Position) ctx->core.width, y);
  964.       line = LineForPosition(ctx, last_pos);
  965.  
  966.       if ( (y < ctx->text.lt.info[line + 1].y) || ((last - first) < 1.0) )
  967.     CreateVScrollBar(ctx);
  968.       else 
  969.     DestroyVScrollBar(ctx);
  970.     }
  971.   
  972.     if (ctx->text.vbar != NULL) 
  973.       XawScrollbarSetThumb(ctx->text.vbar, first, last - first);
  974.   
  975.     if ( (ctx->text.vbar == NULL) != temp) {
  976.       _XawTextNeedsUpdating(ctx, zeroPosition, ctx->text.lastPos);
  977.       if (ctx->text.vbar == NULL)
  978.     _XawTextBuildLineTable (ctx, zeroPosition, FALSE);
  979.     }
  980.   }
  981.   else if (ctx->text.vbar != NULL)
  982.     if (ctx->text.scroll_vert == XawtextScrollWhenNeeded)
  983.       DestroyVScrollBar(ctx);
  984.     else if (ctx->text.scroll_vert == XawtextScrollAlways)
  985.       XawScrollbarSetThumb(ctx->text.vbar, 0.0, 1.0);
  986. }
  987.  
  988. /*
  989.  * This routine is used by Text to notify an associated scrollbar of the
  990.  * correct metrics (position and shown fraction) for the text being currently
  991.  * displayed in the window.
  992.  */
  993.  
  994. void 
  995. _XawTextSetScrollBars(ctx)
  996. TextWidget ctx;
  997. {
  998.   float first, last, widest;
  999.   Boolean temp = (ctx->text.hbar == NULL);
  1000.   Boolean vtemp = (ctx->text.vbar == NULL);
  1001.   
  1002.   CheckVBarScrolling(ctx);
  1003.  
  1004.   if (ctx->text.scroll_horiz == XawtextScrollNever) return;
  1005.  
  1006.   if (ctx->text.vbar != NULL) 
  1007.     widest = (int)(ctx->core.width - ctx->text.vbar->core.width -
  1008.            ctx->text.vbar->core.border_width);
  1009.   else
  1010.     widest = ctx->core.width;
  1011.   widest /= (last = GetWidestLine(ctx));
  1012.   if (ctx->text.scroll_horiz == XawtextScrollWhenNeeded) 
  1013.     if (widest < 1.0)
  1014.       CreateHScrollBar(ctx);
  1015.     else
  1016.       DestroyHScrollBar(ctx);
  1017.  
  1018.   if ( (ctx->text.hbar == NULL) != temp ) {
  1019.     _XawTextBuildLineTable (ctx, ctx->text.lt.top, TRUE);
  1020.     CheckVBarScrolling(ctx);    /* Recheck need for vbar, now that we added
  1021.                    or removed the hbar.*/
  1022.   }
  1023.   
  1024.   if (ctx->text.hbar != NULL) {
  1025.     first = ctx->text.r_margin.left - ctx->text.margin.left;
  1026.     first /= last;
  1027.     XawScrollbarSetThumb(ctx->text.hbar, first, widest); 
  1028.   }
  1029.  
  1030.   if (((ctx->text.hbar == NULL) && (ctx->text.margin.left !=
  1031.                    ctx->text.r_margin.left)) ||
  1032.       (ctx->text.vbar == NULL) != vtemp)
  1033.   {
  1034.     ctx->text.margin.left = ctx->text.r_margin.left;
  1035.     _XawTextNeedsUpdating(ctx, zeroPosition, ctx->text.lastPos);      
  1036.     FlushUpdate(ctx);
  1037.   }
  1038. }
  1039.  
  1040. /*
  1041.  * The routine will scroll the displayed text by lines.  If the arg  is
  1042.  * positive, move up; otherwise, move down. [note: this is really a private
  1043.  * procedure but is used in multiple modules].
  1044.  */
  1045.  
  1046. void
  1047. _XawTextVScroll(ctx, n)
  1048. TextWidget ctx;
  1049. int n;            
  1050. {
  1051.   XawTextPosition top, target;
  1052.   int y;
  1053.   XawTextLineTable * lt = &(ctx->text.lt);
  1054.  
  1055.   if (abs(n) > ctx->text.lt.lines) 
  1056.     n = (n > 0) ? ctx->text.lt.lines : -ctx->text.lt.lines;
  1057.  
  1058.   if (n == 0) return;
  1059.  
  1060.   if (n > 0) {
  1061.     if ( IsValidLine(ctx, n) )
  1062.       top = Min(lt->info[n].position, ctx->text.lastPos);
  1063.     else
  1064.       top = ctx->text.lastPos;
  1065.  
  1066.     y = IsValidLine(ctx, n) ? lt->info[n].y : ctx->core.height;
  1067.     _XawTextBuildLineTable(ctx, top, FALSE);
  1068.     if (top >= ctx->text.lastPos)
  1069.       DisplayTextWindow( (Widget) ctx);
  1070.     else {
  1071.       XCopyArea(XtDisplay(ctx), XtWindow(ctx), XtWindow(ctx), ctx->text.gc,
  1072.         0, y, (int)ctx->core.width, (int)ctx->core.height - y,
  1073.         0, ctx->text.margin.top);
  1074.  
  1075.       PushCopyQueue(ctx, 0, (int) -y);
  1076.       SinkClearToBG(ctx->text.sink, 
  1077.             (Position) 0,
  1078.             (Position) (ctx->text.margin.top + ctx->core.height - y),
  1079.            (Dimension) ctx->core.width, (Dimension) ctx->core.height);
  1080.  
  1081.       if (n < lt->lines) n++; /* update descenders at bottom */
  1082.       _XawTextNeedsUpdating(ctx, lt->info[lt->lines - n].position, 
  1083.                 ctx->text.lastPos);
  1084.       _XawTextSetScrollBars(ctx);
  1085.     }
  1086.   } 
  1087.   else {
  1088.     XawTextPosition updateTo;
  1089.     unsigned int height, clear_height;
  1090.  
  1091.     n = -n;
  1092.     target = lt->top;
  1093.     top = SrcScan(ctx->text.source, target, XawstEOL,
  1094.           XawsdLeft, n+1, FALSE);
  1095.  
  1096.     _XawTextBuildLineTable(ctx, top, FALSE);
  1097.     y = IsValidLine(ctx, n) ? lt->info[n].y : ctx->core.height;
  1098.     updateTo = IsValidLine(ctx, n) ? lt->info[n].position : ctx->text.lastPos;
  1099.     if (IsValidLine(ctx, lt->lines - n))
  1100.       height = lt->info[lt->lines-n].y - ctx->text.margin.top;
  1101.     else if (ctx->core.height - HMargins(ctx))
  1102.       height = ctx->core.height - HMargins(ctx);
  1103.     else
  1104.       height = 0;
  1105.     if (y > (int) ctx->text.margin.top)
  1106.       clear_height = y - ctx->text.margin.top;
  1107.     else
  1108.       clear_height = 0;
  1109.  
  1110.     if ( updateTo == target ) {
  1111.       XCopyArea(XtDisplay(ctx), XtWindow(ctx), XtWindow(ctx), ctx->text.gc, 
  1112.         0, ctx->text.margin.top, (int) ctx->core.width, height, 0, y);
  1113.       PushCopyQueue(ctx, 0, (int) y);
  1114.       SinkClearToBG(ctx->text.sink, (Position) 0, ctx->text.margin.top,
  1115.            (Dimension) ctx->core.width, (Dimension) clear_height);
  1116.       
  1117.       _XawTextNeedsUpdating(ctx, lt->info[0].position, updateTo);
  1118.       _XawTextSetScrollBars(ctx);
  1119.     } 
  1120.     else if (lt->top != target)
  1121.       DisplayTextWindow((Widget)ctx);
  1122.   }
  1123. }
  1124.  
  1125. /*ARGSUSED*/
  1126. static void 
  1127. HScroll(w, closure, callData)
  1128. Widget w;
  1129. XtPointer closure;        /* TextWidget */
  1130. XtPointer callData;        /* #pixels */
  1131. {
  1132.   TextWidget ctx = (TextWidget) closure;
  1133.   Widget tw = (Widget) ctx;
  1134.   Position old_left, pixels = (Position)(int) callData;
  1135.   XRectangle rect, t_rect;
  1136.   
  1137.   _XawTextPrepareToUpdate(ctx);
  1138.  
  1139.   old_left = ctx->text.margin.left;
  1140.   ctx->text.margin.left -= pixels;
  1141.   if (ctx->text.margin.left > ctx->text.r_margin.left) {
  1142.     ctx->text.margin.left = ctx->text.r_margin.left;
  1143.     pixels = old_left - ctx->text.margin.left;
  1144.   }
  1145.   
  1146.   if (pixels > 0) {
  1147.     rect.width = (unsigned short) pixels + ctx->text.margin.right;
  1148.     rect.x = (short) ctx->core.width - (short) rect.width;
  1149.     rect.y = (short) ctx->text.margin.top;
  1150.     rect.height = (unsigned short) ctx->core.height - rect.y;
  1151.  
  1152.     XCopyArea(XtDisplay(tw), XtWindow(tw), XtWindow(tw), ctx->text.gc,
  1153.           pixels, (int) rect.y,
  1154.           (unsigned int) rect.x, (unsigned int) ctx->core.height,
  1155.           0, (int) rect.y);
  1156.  
  1157.     PushCopyQueue(ctx, (int) -pixels, 0);
  1158.   }
  1159.   else if (pixels < 0) {
  1160.     rect.x = 0;
  1161.  
  1162.     if (ctx->text.vbar != NULL)
  1163.       rect.x += (short) (ctx->text.vbar->core.width +
  1164.              ctx->text.vbar->core.border_width);
  1165.  
  1166.     rect.width = (Position) - pixels;
  1167.     rect.y = ctx->text.margin.top;
  1168.     rect.height = ctx->core.height - rect.y;
  1169.  
  1170.     XCopyArea(XtDisplay(tw), XtWindow(tw), XtWindow(tw), ctx->text.gc,
  1171.           (int) rect.x, (int) rect.y,
  1172.           (unsigned int) ctx->core.width - rect.width,
  1173.           (unsigned int) rect.height,
  1174.           (int) rect.x + rect.width, (int) rect.y);
  1175.  
  1176.     PushCopyQueue(ctx, (int) rect.width, 0);
  1177.  
  1178. /*
  1179.  * Redraw the line overflow marks.
  1180.  */
  1181.  
  1182.     t_rect.x = ctx->core.width - ctx->text.margin.right;
  1183.     t_rect.width = ctx->text.margin.right;
  1184.     t_rect.y = rect.y;
  1185.     t_rect.height = rect.height;
  1186.       
  1187.     SinkClearToBG(ctx->text.sink, (Position) t_rect.x, (Position) t_rect.y,
  1188.           (Dimension) t_rect.width, (Dimension) t_rect.height);
  1189.     
  1190.     UpdateTextInRectangle(ctx, &t_rect);
  1191.   }
  1192.  
  1193. /*  
  1194.  * Put in the text that just became visible.
  1195.  */
  1196.  
  1197.   if ( pixels != 0 ) {
  1198.     SinkClearToBG(ctx->text.sink, (Position) rect.x, (Position) rect.y,
  1199.           (Dimension) rect.width, (Dimension) rect.height);
  1200.     
  1201.     UpdateTextInRectangle(ctx, &rect);
  1202.   }
  1203.   _XawTextExecuteUpdate(ctx);
  1204.   _XawTextSetScrollBars(ctx);
  1205. }
  1206.  
  1207. /*ARGSUSED*/
  1208. static void 
  1209. HJump(w, closure, callData)
  1210. Widget w;
  1211. XtPointer closure, callData; /* closure = TextWidget, callData = percent. */
  1212. {
  1213.   TextWidget ctx = (TextWidget) closure;
  1214.   float * percent = (float *) callData;
  1215.   Position move, new_left, old_left = ctx->text.margin.left;
  1216.  
  1217.   new_left = ctx->text.r_margin.left;
  1218.   new_left -= (Position) (*percent * GetWidestLine(ctx));
  1219.   move = old_left - new_left;
  1220.  
  1221.   if (abs(move) < (int)ctx->core.width) {
  1222.     HScroll(w, (XtPointer) ctx, (XtPointer) move);
  1223.     return;
  1224.   }
  1225.   _XawTextPrepareToUpdate(ctx);
  1226.   ctx->text.margin.left = new_left;
  1227.   if (XtIsRealized((Widget) ctx)) DisplayTextWindow((Widget) ctx); 
  1228.   _XawTextExecuteUpdate(ctx);
  1229. }
  1230.  
  1231. /*    Function Name: UpdateTextInLine
  1232.  *    Description: Updates some text in a given line.
  1233.  *    Arguments: ctx - the text widget.
  1234.  *                 line - the line number (in the line table) of this line.
  1235.  *                 left, right - left and right pixel offsets of the
  1236.  *                               area to update.
  1237.  *    Returns: none.
  1238.  */
  1239.  
  1240. static void
  1241. UpdateTextInLine(ctx, line, left, right)
  1242. TextWidget ctx;
  1243. int line;
  1244. Position left, right;
  1245. {
  1246.   XawTextPosition pos1, pos2; 
  1247.   int width, height, local_left, local_width;
  1248.   XawTextLineTableEntry * lt = ctx->text.lt.info + line;
  1249.  
  1250.   if ( ((int)(lt->textWidth + ctx->text.margin.left) < left) ||
  1251.        ( ctx->text.margin.left > right ) )
  1252.     return;            /* no need to update. */
  1253.  
  1254.   local_width = left - ctx->text.margin.left;
  1255.   XawTextSinkFindPosition(ctx->text.sink, lt->position,
  1256.               (int) ctx->text.margin.left, 
  1257.               local_width, FALSE, &pos1, &width, &height);
  1258.  
  1259.   if (right >= (Position) lt->textWidth - ctx->text.margin.left) 
  1260.     if ( (IsValidLine(ctx, line + 1)) &&
  1261.      (ctx->text.lt.info[line + 1].position <= ctx->text.lastPos) )
  1262.       pos2 = SrcScan( ctx->text.source, (lt + 1)->position, XawstPositions, 
  1263.                XawsdLeft, 1, TRUE);
  1264.     else 
  1265.       pos2 = GETLASTPOS;
  1266.   else {
  1267.     XawTextPosition t_pos;
  1268.  
  1269.     local_left = ctx->text.margin.left + width;
  1270.     local_width = right  - local_left;
  1271.     XawTextSinkFindPosition(ctx->text.sink, pos1, local_left,
  1272.                 local_width, FALSE, &pos2, &width, &height);
  1273.     
  1274.     t_pos = SrcScan( ctx->text.source, pos2,
  1275.              XawstPositions, XawsdRight, 1, TRUE);
  1276.     if (t_pos < (lt + 1)->position)
  1277.       pos2 = t_pos;
  1278.   }
  1279.  
  1280.   _XawTextNeedsUpdating(ctx, pos1, pos2);
  1281. }
  1282.  
  1283. /*
  1284.  * The routine will scroll the displayed text by pixels.  If the calldata is
  1285.  * positive, move up; otherwise, move down.
  1286.  */
  1287.  
  1288. /*ARGSUSED*/
  1289. static void 
  1290. VScroll(w, closure, callData)
  1291. Widget w;
  1292. XtPointer closure;        /* TextWidget */
  1293. XtPointer callData;        /* #pixels */
  1294. {
  1295.   TextWidget ctx = (TextWidget)closure;
  1296.   int height, lines = (int) callData;
  1297.  
  1298.   height = ctx->core.height - VMargins(ctx);
  1299.   if (height < 1)
  1300.     height = 1;
  1301.   lines = (int) (lines * (int) ctx->text.lt.lines) / height;
  1302.   _XawTextPrepareToUpdate(ctx);
  1303.   _XawTextVScroll(ctx, lines);
  1304.   _XawTextExecuteUpdate(ctx);
  1305. }
  1306.  
  1307. /*
  1308.  * The routine "thumbs" the displayed text. Thumbing means reposition the
  1309.  * displayed view of the source to a new position determined by a fraction
  1310.  * of the way from beginning to end. Ideally, this should be determined by
  1311.  * the number of displayable lines in the source. This routine does it as a
  1312.  * fraction of the first position and last position and then normalizes to
  1313.  * the start of the line containing the position.
  1314.  *
  1315.  * BUG/deficiency: The normalize to line portion of this routine will
  1316.  * cause thumbing to always position to the start of the source.
  1317.  */
  1318.  
  1319. /*ARGSUSED*/
  1320. static void 
  1321. VJump(w, closure, callData)
  1322. Widget w;
  1323. XtPointer closure, callData; /* closuer = TextWidget, callData = percent. */
  1324. {
  1325.   float * percent = (float *) callData;
  1326.   TextWidget ctx = (TextWidget)closure;
  1327.   XawTextPosition position, old_top, old_bot;
  1328.   XawTextLineTable * lt = &(ctx->text.lt);
  1329.  
  1330.   _XawTextPrepareToUpdate(ctx);
  1331.   old_top = lt->top;
  1332.   if ( (lt->lines > 0) && (IsValidLine(ctx, lt->lines - 1)) )
  1333.     old_bot = lt->info[lt->lines - 1].position;
  1334.   else
  1335.     old_bot = ctx->text.lastPos;
  1336.  
  1337.   position = (long) (*percent * (float) ctx->text.lastPos);
  1338.   position= SrcScan(ctx->text.source, position, XawstEOL, XawsdLeft, 1, FALSE);
  1339.   if ( (position >= old_top) && (position <= old_bot) ) {
  1340.     int line = 0;
  1341.     for (;(line < lt->lines) && (position > lt->info[line].position) ; line++);
  1342.     _XawTextVScroll(ctx, line);
  1343.   }
  1344.   else {
  1345.     XawTextPosition new_bot;
  1346.     _XawTextBuildLineTable(ctx, position, FALSE);
  1347.     new_bot = IsValidLine(ctx, lt->lines-1) ? lt->info[lt->lines-1].position 
  1348.                                             : ctx->text.lastPos;
  1349.  
  1350.     if ((old_top >= lt->top) && (old_top <= new_bot)) {
  1351.       int line = 0;
  1352.       for (;(line < lt->lines) && (old_top > lt->info[line].position); line++);
  1353.       _XawTextBuildLineTable(ctx, old_top, FALSE);
  1354.       _XawTextVScroll(ctx, -line);
  1355.     }
  1356.     else 
  1357.       DisplayTextWindow( (Widget) ctx);
  1358.   }
  1359.   _XawTextExecuteUpdate(ctx);
  1360. }
  1361.  
  1362. static Boolean
  1363. MatchSelection(selection, s)
  1364. Atom            selection;
  1365. XawTextSelection    *s;
  1366. {
  1367.     Atom    *match;
  1368.     int        count;
  1369.  
  1370.     for (count = 0, match = s->selections; count < s->atom_count; match++, count++)
  1371.     if (*match == selection)
  1372.         return True;
  1373.     return False;
  1374. }
  1375.  
  1376. static Boolean 
  1377. ConvertSelection(w, selection, target, type, value, length, format)
  1378. Widget w;
  1379. Atom *selection, *target, *type;
  1380. XtPointer *value;
  1381. unsigned long *length;
  1382. int *format;
  1383. {
  1384.   Display* d = XtDisplay(w);
  1385.   TextWidget ctx = (TextWidget)w;
  1386.   Widget src = ctx->text.source;
  1387.   XawTextEditType edit_mode;
  1388.   Arg args[1];
  1389.   XawTextSelectionSalt    *salt = NULL;
  1390.   XawTextSelection  *s;
  1391.  
  1392.   if (*target == XA_TARGETS(d)) {
  1393.     Atom* targetP, * std_targets;
  1394.     unsigned long std_length;
  1395.  
  1396.     if ( SrcCvtSel(src, selection, target, type, value, length, format) ) 
  1397.     return True;
  1398.  
  1399.     XmuConvertStandardSelection(w, ctx->text.time, selection, 
  1400.                 target, type, (caddr_t*)&std_targets,
  1401.                 &std_length, format);
  1402.     
  1403.     *value = XtMalloc((unsigned) sizeof(Atom)*(std_length + 7));
  1404.     targetP = *(Atom**)value;
  1405.     *length = std_length + 6;
  1406.     *targetP++ = XA_STRING;
  1407.     *targetP++ = XA_TEXT(d);
  1408.     *targetP++ = XA_COMPOUND_TEXT(d);
  1409.     *targetP++ = XA_LENGTH(d);
  1410.     *targetP++ = XA_LIST_LENGTH(d);
  1411.     *targetP++ = XA_CHARACTER_POSITION(d);
  1412.  
  1413.     XtSetArg(args[0], XtNeditType,&edit_mode);
  1414.     XtGetValues(src, args, ONE);
  1415.  
  1416.     if (edit_mode == XawtextEdit) {
  1417.       *targetP++ = XA_DELETE(d);
  1418.       (*length)++;
  1419.     }
  1420.     bcopy((char*)std_targets, (char*)targetP, sizeof(Atom)*std_length);
  1421.     XtFree((char*)std_targets);
  1422.     *type = XA_ATOM;
  1423.     *format = 32;
  1424.     return True;
  1425.   }
  1426.   
  1427.   if ( SrcCvtSel(src, selection, target, type, value, length, format) )
  1428.     return True;
  1429.  
  1430.   if (MatchSelection (*selection, &ctx->text.s))
  1431.     s = &ctx->text.s;
  1432.   else
  1433.   {
  1434.     for (salt = ctx->text.salt; salt; salt = salt->next)
  1435.     if (MatchSelection (*selection, &salt->s))
  1436.         break;
  1437.     if (!salt)
  1438.     return False;
  1439.     s = &salt->s;
  1440.   }
  1441.   if (*target == XA_STRING ||
  1442.       *target == XA_TEXT(d) ||
  1443.       *target == XA_COMPOUND_TEXT(d)) {
  1444.     if (*target == XA_COMPOUND_TEXT(d))
  1445.       *type = *target;
  1446.     else
  1447.       *type = XA_STRING;
  1448.     if (!salt)
  1449.     {
  1450.     *value = _XawTextGetSTRING(ctx, s->left, s->right);
  1451.     *length = strlen(*value);
  1452.     }
  1453.     else
  1454.     {
  1455.     *value = XtMalloc (salt->length + 1);
  1456.     strcpy (*value, salt->contents);
  1457.     *length = salt->length;
  1458.     }
  1459.     *format = 8;
  1460.     return True;
  1461.   }
  1462.  
  1463.   if ( (*target == XA_LIST_LENGTH(d)) || (*target == XA_LENGTH(d)) ) {
  1464.     long * temp;
  1465.     
  1466.     temp = (long *) XtMalloc(sizeof(long));
  1467.     if (*target == XA_LIST_LENGTH(d))
  1468.       *temp = 1L;
  1469.     else            /* *target == XA_LENGTH(d) */
  1470.       *temp = (long) (s->right - s->left);
  1471.     
  1472.     *value = (caddr_t) temp;
  1473.     *type = XA_INTEGER;
  1474.     *length = 1L;
  1475.     *format = 32;
  1476.     return True;
  1477.   }
  1478.  
  1479.   if (*target == XA_CHARACTER_POSITION(d)) {
  1480.     long * temp;
  1481.     
  1482.     temp = (long *) XtMalloc(2 * sizeof(long));
  1483.     temp[0] = (long) (s->left + 1);
  1484.     temp[1] = s->right;
  1485.     *value = (caddr_t) temp;
  1486.     *type = XA_SPAN(d);
  1487.     *length = 2L;
  1488.     *format = 32;
  1489.     return True;
  1490.   }
  1491.  
  1492.   if (*target == XA_DELETE(d)) {
  1493.     void _XawTextZapSelection(); /* From TextAction.c */
  1494.     
  1495.     if (!salt)
  1496.     _XawTextZapSelection( ctx, (XEvent *) NULL, TRUE);
  1497.     *value = NULL;
  1498.     *type = XA_NULL(d);
  1499.     *length = 0;
  1500.     *format = 32;
  1501.     return True;
  1502.   }
  1503.  
  1504.   if (XmuConvertStandardSelection(w, ctx->text.time, selection, target, type,
  1505.                   (caddr_t *)value, length, format))
  1506.     return True;
  1507.   
  1508.   /* else */
  1509.   return False;
  1510. }
  1511.  
  1512. /*    Function Name: GetCutBuffferNumber
  1513.  *    Description: Returns the number of the cut buffer.
  1514.  *    Arguments: atom - the atom to check.
  1515.  *    Returns: the number of the cut buffer representing this atom or
  1516.  *               NOT_A_CUT_BUFFER.
  1517.  */
  1518.  
  1519. #define NOT_A_CUT_BUFFER -1
  1520.  
  1521. static int
  1522. GetCutBufferNumber(atom)
  1523. register Atom atom;
  1524. {
  1525.   if (atom == XA_CUT_BUFFER0) return(0);
  1526.   if (atom == XA_CUT_BUFFER1) return(1);
  1527.   if (atom == XA_CUT_BUFFER2) return(2);
  1528.   if (atom == XA_CUT_BUFFER3) return(3);
  1529.   if (atom == XA_CUT_BUFFER4) return(4);
  1530.   if (atom == XA_CUT_BUFFER5) return(5);
  1531.   if (atom == XA_CUT_BUFFER6) return(6);
  1532.   if (atom == XA_CUT_BUFFER7) return(7);
  1533.   return(NOT_A_CUT_BUFFER);
  1534. }
  1535.  
  1536. static void 
  1537. LoseSelection(w, selection)
  1538. Widget w;
  1539. Atom *selection;
  1540. {
  1541.   TextWidget ctx = (TextWidget) w;
  1542.   register Atom* atomP;
  1543.   register int i;
  1544.   XawTextSelectionSalt    *salt, *prevSalt, *nextSalt;
  1545.  
  1546.   _XawTextPrepareToUpdate(ctx);
  1547.  
  1548.   atomP = ctx->text.s.selections;
  1549.   for (i = 0 ; i < ctx->text.s.atom_count; i++, atomP++)
  1550.     if ( (*selection == *atomP) || 
  1551.     (GetCutBufferNumber(*atomP) != NOT_A_CUT_BUFFER) )/* is a cut buffer */
  1552.       *atomP = (Atom)0;
  1553.  
  1554.   while (ctx->text.s.atom_count &&
  1555.      ctx->text.s.selections[ctx->text.s.atom_count-1] == 0)
  1556.     ctx->text.s.atom_count--;
  1557.  
  1558. /*
  1559.  * Must walk the selection list in opposite order from UnsetSelection.
  1560.  */
  1561.  
  1562.   atomP = ctx->text.s.selections;
  1563.   for (i = 0 ; i < ctx->text.s.atom_count; i++, atomP++)
  1564.     if (*atomP == (Atom)0) {
  1565.       *atomP = ctx->text.s.selections[--ctx->text.s.atom_count];
  1566.       while (ctx->text.s.atom_count &&
  1567.          ctx->text.s.selections[ctx->text.s.atom_count-1] == 0)
  1568.     ctx->text.s.atom_count--;
  1569.     }
  1570.   
  1571.   if (ctx->text.s.atom_count == 0)
  1572.     ModifySelection(ctx, ctx->text.insertPos, ctx->text.insertPos);
  1573.       
  1574.   if (ctx->text.old_insert >= 0) /* Update in progress. */
  1575.     _XawTextExecuteUpdate(ctx);
  1576.  
  1577.     prevSalt = 0;
  1578.     for (salt = ctx->text.salt; salt; salt = nextSalt)
  1579.     {
  1580.         atomP = salt->s.selections;
  1581.     nextSalt = salt->next;
  1582.         for (i = 0 ; i < salt->s.atom_count; i++, atomP++)
  1583.         if (*selection == *atomP)
  1584.         *atomP = (Atom)0;
  1585.         
  1586.         while (salt->s.atom_count &&
  1587.            salt->s.selections[salt->s.atom_count-1] == 0)
  1588.     {
  1589.         salt->s.atom_count--;
  1590.     }
  1591.         
  1592.         /*
  1593.          * Must walk the selection list in opposite order from UnsetSelection.
  1594.          */
  1595.         
  1596.         atomP = salt->s.selections;
  1597.         for (i = 0 ; i < salt->s.atom_count; i++, atomP++)
  1598.             if (*atomP == (Atom)0)
  1599.          {
  1600.                 *atomP = salt->s.selections[--salt->s.atom_count];
  1601.                 while (salt->s.atom_count &&
  1602.                   salt->s.selections[salt->s.atom_count-1] == 0)
  1603.                 salt->s.atom_count--;
  1604.             }
  1605.     if (salt->s.atom_count == 0)
  1606.     {
  1607.         XtFree ((char *) salt->s.selections);
  1608.         XtFree (salt->contents);
  1609.         if (prevSalt)
  1610.         prevSalt->next = nextSalt;
  1611.         else
  1612.         ctx->text.salt = nextSalt;
  1613.         XtFree ((char *) salt);
  1614.     }
  1615.     else
  1616.         prevSalt = salt;
  1617.     }
  1618. }
  1619.  
  1620. void
  1621. _XawTextSaltAwaySelection (ctx, selections, num_atoms)
  1622. TextWidget ctx;
  1623. Atom    *selections;
  1624. int    num_atoms;
  1625. {
  1626.     XawTextSelectionSalt    *salt;
  1627.     int                i, j;
  1628.  
  1629.     for (i = 0; i < num_atoms; i++)
  1630.     LoseSelection ((Widget) ctx, selections + i);
  1631.     if (num_atoms == 0)
  1632.     return;
  1633.     salt = (XawTextSelectionSalt *) XtMalloc (sizeof (XawTextSelectionSalt));
  1634.     if (!salt)
  1635.     return;
  1636.     salt->s.selections = (Atom *) XtMalloc (num_atoms * sizeof (Atom));
  1637.     if (!salt->s.selections)
  1638.     {
  1639.     XtFree ((char *) salt);
  1640.     return;
  1641.     }
  1642.     salt->s.left = ctx->text.s.left;
  1643.     salt->s.right = ctx->text.s.right;
  1644.     salt->s.type = ctx->text.s.type;
  1645.     salt->contents = _XawTextGetSTRING(ctx, ctx->text.s.left, ctx->text.s.right);
  1646.     salt->length = strlen (salt->contents);
  1647.     salt->next = ctx->text.salt;
  1648.     ctx->text.salt = salt;
  1649.     j = 0;
  1650.     for (i = 0; i < num_atoms; i++)
  1651.     {
  1652.     if (GetCutBufferNumber (selections[i]) == NOT_A_CUT_BUFFER)
  1653.     {
  1654.         salt->s.selections[j++] = selections[i];
  1655.         XtOwnSelection ((Widget) ctx, selections[i], ctx->text.time,
  1656.                 ConvertSelection, LoseSelection, NULL);
  1657.     }
  1658.     }
  1659.     salt->s.atom_count = j;
  1660. }
  1661.  
  1662. static void 
  1663. _SetSelection(ctx, left, right, selections, count)
  1664. TextWidget ctx;
  1665. XawTextPosition left, right;
  1666. Atom *selections;
  1667. Cardinal count;
  1668. {
  1669.   XawTextPosition pos;
  1670.   
  1671.   if (left < ctx->text.s.left) {
  1672.     pos = Min(right, ctx->text.s.left);
  1673.     _XawTextNeedsUpdating(ctx, left, pos);
  1674.   }
  1675.   if (left > ctx->text.s.left) {
  1676.     pos = Min(left, ctx->text.s.right);
  1677.     _XawTextNeedsUpdating(ctx, ctx->text.s.left, pos);
  1678.   }
  1679.   if (right < ctx->text.s.right) {
  1680.     pos = Max(right, ctx->text.s.left);
  1681.     _XawTextNeedsUpdating(ctx, pos, ctx->text.s.right);
  1682.   }
  1683.   if (right > ctx->text.s.right) {
  1684.     pos = Max(left, ctx->text.s.right);
  1685.     _XawTextNeedsUpdating(ctx, pos, right);
  1686.   }
  1687.   
  1688.   ctx->text.s.left = left;
  1689.   ctx->text.s.right = right;
  1690.  
  1691.   SrcSetSelection(ctx->text.source, left, right,
  1692.           (count == 0) ? None : selections[0]);
  1693.  
  1694.   if (left < right) {
  1695.     Widget w = (Widget) ctx;
  1696.     int buffer;
  1697.     
  1698.     while (count) {
  1699.       Atom selection = selections[--count];
  1700. /*
  1701.  * If this is a cut buffer.
  1702.  */
  1703.  
  1704.       if ((buffer = GetCutBufferNumber(selection)) != NOT_A_CUT_BUFFER) {
  1705.     unsigned char *ptr, *tptr;
  1706.     unsigned int amount, max_len = MAX_CUT_LEN(XtDisplay(w));
  1707.     unsigned long len;
  1708.  
  1709.     tptr= ptr= (unsigned char *) _XawTextGetSTRING(ctx, ctx->text.s.left, 
  1710.                                ctx->text.s.right);
  1711.     if (buffer == 0) {
  1712.       _CreateCutBuffers(XtDisplay(w));
  1713.       XRotateBuffers(XtDisplay(w), 1);
  1714.     }
  1715.     amount = Min ( (len = strlen((char *)ptr)), max_len);
  1716.     XChangeProperty(XtDisplay(w), RootWindow(XtDisplay(w), 0), selection, 
  1717.             XA_STRING, 8, PropModeReplace, ptr, amount);
  1718.  
  1719.     while (len > max_len) {
  1720.         len -= max_len;
  1721.         tptr += max_len;
  1722.         amount = Min (len, max_len);
  1723.         XChangeProperty(XtDisplay(w), RootWindow(XtDisplay(w), 0), 
  1724.                 selection, XA_STRING, 8, PropModeAppend, 
  1725.                 tptr, amount);
  1726.     }
  1727.     XtFree ((char *)ptr);
  1728.       }
  1729.       else            /* This is a real selection. */
  1730.     XtOwnSelection(w, selection, ctx->text.time,
  1731.                ConvertSelection, LoseSelection, NULL);
  1732.     }
  1733.   }
  1734.   else
  1735.     XawTextUnsetSelection((Widget)ctx);
  1736. }
  1737.  
  1738. /*
  1739.  * This internal routine deletes the text from pos1 to pos2 in a source and
  1740.  * then inserts, at pos1, the text that was passed. As a side effect it
  1741.  * "invalidates" that portion of the displayed text (if any).
  1742.  *
  1743.  * NOTE: It is illegal to call this routine unless there is a valid line table!
  1744.  */
  1745.  
  1746. int 
  1747. _XawTextReplace (ctx, pos1, pos2, text)
  1748. TextWidget ctx;
  1749. XawTextPosition pos1, pos2;
  1750. XawTextBlock *text;
  1751. {
  1752.   int i, line1, delta, error;
  1753.   XawTextPosition updateFrom, updateTo;
  1754.   Widget src = ctx->text.source;
  1755.   XawTextEditType edit_mode;
  1756.   Arg args[1];
  1757.   Boolean tmp = ctx->text.update_disabled;
  1758.  
  1759.   ctx->text.update_disabled = True; /* No redisplay during replacement. */
  1760.  
  1761. /*
  1762.  * The insertPos may not always be set to the right spot in XawtextAppend 
  1763.  */
  1764.  
  1765.   XtSetArg(args[0], XtNeditType, &edit_mode);
  1766.   XtGetValues(src, args, ONE);
  1767.  
  1768.   if ((pos1 == ctx->text.insertPos) && (edit_mode == XawtextAppend)) {
  1769.     ctx->text.insertPos = ctx->text.lastPos;
  1770.     pos2 = SrcScan(src, ctx->text.insertPos, XawstPositions, XawsdRight,
  1771.            (ctx->text.insertPos - pos1), TRUE);
  1772.     pos1 = ctx->text.insertPos;
  1773.     if ( (pos1 == pos2) && (text->length == 0) ) {
  1774.       ctx->text.update_disabled = tmp; /* restore redisplay */
  1775.       return( XawEditError );
  1776.     }
  1777.   }
  1778.  
  1779.   updateFrom = SrcScan(src, pos1, XawstWhiteSpace, XawsdLeft, 1, FALSE);
  1780.   updateFrom = Max(updateFrom, ctx->text.lt.top);
  1781.  
  1782.   line1 = LineForPosition(ctx, updateFrom);
  1783.   if ( (error = SrcReplace(src, pos1, pos2, text)) != 0) {
  1784.     ctx->text.update_disabled = tmp; /* restore redisplay */
  1785.     return(error);
  1786.   }
  1787.  
  1788.   XawTextUnsetSelection((Widget)ctx);
  1789.  
  1790.   ctx->text.lastPos = GETLASTPOS;
  1791.   if (ctx->text.lt.top >= ctx->text.lastPos) {
  1792.     _XawTextBuildLineTable(ctx, ctx->text.lastPos, FALSE);
  1793.     ClearWindow( (Widget) ctx);
  1794.     ctx->text.update_disabled = tmp; /* restore redisplay */
  1795.     return(0);            /* Things are fine. */
  1796.   }
  1797.  
  1798.   ctx->text.single_char = (text->length <= 1 && pos2 - pos1 <= 1);
  1799.  
  1800.   delta = text->length - (pos2 - pos1);
  1801.  
  1802.   if (delta < ctx->text.lastPos) {
  1803.     for (pos2 += delta, i = 0; i < ctx->text.numranges; i++) {
  1804.       if (ctx->text.updateFrom[i] > pos1)
  1805.     ctx->text.updateFrom[i] += delta;
  1806.       if (ctx->text.updateTo[i] >= pos1)
  1807.     ctx->text.updateTo[i] += delta;
  1808.     }
  1809.   }
  1810.   
  1811.   /* 
  1812.    * fixup all current line table entries to reflect edit.
  1813.    * %%% it is not legal to do arithmetic on positions.
  1814.    * using Scan would be more proper.
  1815.    */ 
  1816.   if (delta != 0) {
  1817.     XawTextLineTableEntry *lineP;
  1818.     i = LineForPosition(ctx, pos1) + 1;
  1819.     for (lineP = ctx->text.lt.info + i; i <= ctx->text.lt.lines; i++, lineP++)
  1820.       lineP->position += delta;
  1821.   }
  1822.   
  1823.   /*
  1824.    * Now process the line table and fixup in case edits caused
  1825.    * changes in line breaks. If we are breaking on word boundaries,
  1826.    * this code checks for moving words to and from lines.
  1827.    */
  1828.   
  1829.   if (IsPositionVisible(ctx, updateFrom)) {
  1830.     updateTo = _BuildLineTable(ctx, 
  1831.                    ctx->text.lt.info[line1].position, pos1, line1);
  1832.     _XawTextNeedsUpdating(ctx, updateFrom, updateTo);
  1833.   }
  1834.  
  1835.   ctx->text.update_disabled = tmp; /* restore redisplay */
  1836.   return(0);            /* Things are fine. */
  1837. }
  1838.  
  1839. /*
  1840.  * This routine will display text between two arbitrary source positions.
  1841.  * In the event that this span contains highlighted text for the selection, 
  1842.  * only that portion will be displayed highlighted.
  1843.  *
  1844.  * NOTE: it is illegal to call this routine unless there
  1845.  *       is a valid line table! 
  1846.  */
  1847.  
  1848. static void 
  1849. DisplayText(w, pos1, pos2)
  1850. Widget w;
  1851. XawTextPosition pos1, pos2;
  1852. {
  1853.   TextWidget ctx = (TextWidget)w;
  1854.   Position x, y;
  1855.   int height, line, i, lastPos = ctx->text.lastPos;
  1856.   XawTextPosition startPos, endPos;
  1857.   Boolean clear_eol, done_painting;
  1858.  
  1859.   pos1 = (pos1 < ctx->text.lt.top) ? ctx->text.lt.top : pos1;
  1860.   pos2 = FindGoodPosition(ctx, pos2);
  1861.   if ( (pos1 >= pos2) || !LineAndXYForPosition(ctx, pos1, &line, &x, &y) )
  1862.     return;            /* line not visible, or pos1 >= pos2. */
  1863.  
  1864.   for ( startPos = pos1, i = line; IsValidLine(ctx, i) && 
  1865.                                    (i < ctx->text.lt.lines) ; i++) {
  1866.  
  1867.     
  1868.     if ( (endPos = ctx->text.lt.info[i + 1].position) > pos2 ) {
  1869.       clear_eol = ((endPos = pos2) >= lastPos);
  1870.       done_painting = (!clear_eol || ctx->text.single_char);
  1871.     }
  1872.     else {
  1873.       clear_eol = TRUE;
  1874.       done_painting = FALSE;
  1875.     }
  1876.  
  1877.     height = ctx->text.lt.info[i + 1].y - ctx->text.lt.info[i].y;
  1878.  
  1879.     if ( (endPos > startPos) ) {
  1880.       if ( (x == (Position) ctx->text.margin.left) && (x > 0) )
  1881.      SinkClearToBG (ctx->text.sink,
  1882.             (Position) 0, y, 
  1883.             (Dimension) ctx->text.margin.left, (Dimension)height); 
  1884.  
  1885.       if ( (startPos >= ctx->text.s.right) || (endPos <= ctx->text.s.left) ) 
  1886.     XawTextSinkDisplayText(ctx->text.sink, x, y, startPos, endPos, FALSE);
  1887.       else if ((startPos >= ctx->text.s.left) && (endPos <= ctx->text.s.right))
  1888.     XawTextSinkDisplayText(ctx->text.sink, x, y, startPos, endPos, TRUE);
  1889.       else {
  1890.     DisplayText(w, startPos, ctx->text.s.left);
  1891.     DisplayText(w, Max(startPos, ctx->text.s.left),
  1892.             Min(endPos, ctx->text.s.right));
  1893.     DisplayText(w, ctx->text.s.right, endPos);
  1894.       }
  1895.     }
  1896.     startPos = endPos;
  1897.     if (clear_eol) {
  1898.     SinkClearToBG(ctx->text.sink, 
  1899.               (Position) (ctx->text.lt.info[i].textWidth +
  1900.                   ctx->text.margin.left),
  1901.               (Position) y, w->core.width, (Dimension) height);
  1902.  
  1903.     /*
  1904.      * We only get here if single character is true, and we need
  1905.      * to clear to the end of the screen.  We know that since there
  1906.      * was only on character deleted that this is the same
  1907.      * as clearing an extra line, so we do this, and are done.
  1908.      * 
  1909.      * This a performance hack, and a pretty gross one, but it works.
  1910.      *
  1911.      * Chris Peterson 11/13/89.
  1912.      */
  1913.  
  1914.     if (done_painting) {
  1915.         y += height;
  1916.         SinkClearToBG(ctx->text.sink, 
  1917.               (Position) ctx->text.margin.left, (Position) y, 
  1918.               w->core.width, (Dimension) height);
  1919.  
  1920.         break;        /* set single_char to FALSE and return. */
  1921.     }
  1922.     }
  1923.  
  1924.     x = (Position) ctx->text.margin.left;
  1925.     y = ctx->text.lt.info[i + 1].y;
  1926.     if ( done_painting
  1927.      || (y >= (int)(ctx->core.height - ctx->text.margin.bottom)) )
  1928.       break;
  1929.   }
  1930.   ctx->text.single_char = FALSE;
  1931. }
  1932.  
  1933. /*
  1934.  * This routine implements multi-click selection in a hardwired manner.
  1935.  * It supports multi-click entity cycling (char, word, line, file) and mouse
  1936.  * motion adjustment of the selected entitie (i.e. select a word then, with
  1937.  * button still down, adjust wich word you really meant by moving the mouse).
  1938.  * [NOTE: This routine is to be replaced by a set of procedures that
  1939.  * will allows clients to implements a wide class of draw through and
  1940.  * multi-click selection user interfaces.]
  1941.  */
  1942.  
  1943. static void 
  1944. DoSelection (ctx, pos, time, motion)
  1945. TextWidget ctx;
  1946. XawTextPosition pos;
  1947. Time time;
  1948. Boolean motion;
  1949. {
  1950.   XawTextPosition newLeft, newRight;
  1951.   XawTextSelectType newType, *sarray;
  1952.   Widget src = ctx->text.source;
  1953.  
  1954.   if (motion)
  1955.     newType = ctx->text.s.type;
  1956.   else {
  1957.     if ( (abs((long) time - (long) ctx->text.lasttime) < MULTI_CLICK_TIME) &&
  1958.      ((pos >= ctx->text.s.left) && (pos <= ctx->text.s.right))) {
  1959.       sarray = ctx->text.sarray;
  1960.       for (;*sarray != XawselectNull && *sarray != ctx->text.s.type; sarray++);
  1961.  
  1962.       if (*sarray == XawselectNull)
  1963.     newType = *(ctx->text.sarray);
  1964.       else {
  1965.     newType = *(sarray + 1);
  1966.     if (newType == XawselectNull) 
  1967.       newType = *(ctx->text.sarray);
  1968.       }
  1969.     } 
  1970.     else                                   /* single-click event */
  1971.       newType = *(ctx->text.sarray);
  1972.  
  1973.     ctx->text.lasttime = time;
  1974.   }
  1975.   switch (newType) {
  1976.   case XawselectPosition: 
  1977.     newLeft = newRight = pos;
  1978.     break;
  1979.   case XawselectChar: 
  1980.     newLeft = pos;
  1981.     newRight = SrcScan(src, pos, XawstPositions, XawsdRight, 1, FALSE);
  1982.     break;
  1983.   case XawselectWord: 
  1984.   case XawselectParagraph: 
  1985.     {
  1986.       XawTextScanType stype;
  1987.  
  1988.       if (newType == XawselectWord)
  1989.         stype = XawstWhiteSpace;
  1990.       else
  1991.     stype = XawstParagraph;
  1992.  
  1993.       /*
  1994.        * Somewhat complicated, but basically I treat the space between
  1995.        * two objects as another object.  The object that I am currently
  1996.        * in then becomes the end of the selection.
  1997.        * 
  1998.        * Chris Peterson - 4/19/90.
  1999.        */
  2000.  
  2001.       newRight = SrcScan(ctx->text.source, pos, stype, XawsdRight, 1, FALSE);
  2002.       newRight =SrcScan(ctx->text.source, newRight,stype,XawsdLeft,1, FALSE);
  2003.  
  2004.       if (pos != newRight) 
  2005.     newLeft = SrcScan(ctx->text.source, pos, stype, XawsdLeft, 1, FALSE);
  2006.       else
  2007.     newLeft = pos;
  2008.  
  2009.       newLeft =SrcScan(ctx->text.source, newLeft, stype, XawsdRight,1,FALSE);
  2010.  
  2011.       if (newLeft > newRight) {
  2012.       XawTextPosition temp = newLeft;
  2013.       newLeft = newRight;
  2014.       newRight = temp;
  2015.       }
  2016.     }
  2017.     break;
  2018.   case XawselectLine: 
  2019.     newLeft = SrcScan(src, pos, XawstEOL, XawsdLeft, 1, FALSE);
  2020.     newRight = SrcScan(src, pos, XawstEOL, XawsdRight, 1, FALSE);
  2021.     break;
  2022.   case XawselectAll: 
  2023.     newLeft = SrcScan(src, pos, XawstAll, XawsdLeft, 1, FALSE);
  2024.     newRight = SrcScan(src, pos, XawstAll, XawsdRight, 1, FALSE);
  2025.     break;
  2026.   default:
  2027.     XtAppWarning(XtWidgetToApplicationContext((Widget) ctx),
  2028.            "Text Widget: empty selection array.");
  2029.     return;
  2030.   }
  2031.  
  2032.   if ( (newLeft != ctx->text.s.left) || (newRight != ctx->text.s.right)
  2033.       || (newType != ctx->text.s.type)) {
  2034.     ModifySelection(ctx, newLeft, newRight);
  2035.     if (pos - ctx->text.s.left < ctx->text.s.right - pos)
  2036.       ctx->text.insertPos = newLeft;
  2037.     else 
  2038.       ctx->text.insertPos = newRight;
  2039.     ctx->text.s.type = newType;
  2040.   }
  2041.   if (!motion) { /* setup so we can freely mix select extend calls*/
  2042.     ctx->text.origSel.type = ctx->text.s.type;
  2043.     ctx->text.origSel.left = ctx->text.s.left;
  2044.     ctx->text.origSel.right = ctx->text.s.right;
  2045.  
  2046.     if (pos >= ctx->text.s.left + ((ctx->text.s.right - ctx->text.s.left) / 2))
  2047.       ctx->text.extendDir = XawsdRight;
  2048.     else
  2049.       ctx->text.extendDir = XawsdLeft;
  2050.   }
  2051. }
  2052.  
  2053. /*
  2054.  * This routine implements extension of the currently selected text in
  2055.  * the "current" mode (i.e. char word, line, etc.). It worries about
  2056.  * extending from either end of the selection and handles the case when you
  2057.  * cross through the "center" of the current selection (e.g. switch which
  2058.  * end you are extending!).
  2059.  * [NOTE: This routine will be replaced by a set of procedures that
  2060.  * will allows clients to implements a wide class of draw through and
  2061.  * multi-click selection user interfaces.]
  2062. */
  2063.  
  2064. static void 
  2065. ExtendSelection (ctx, pos, motion)
  2066. TextWidget ctx;
  2067. XawTextPosition pos;
  2068. Boolean motion;
  2069. {
  2070.   XawTextScanDirection dir;
  2071.  
  2072.   if (!motion) {        /* setup for extending selection */
  2073.     if (ctx->text.s.left == ctx->text.s.right) /* no current selection. */
  2074.       ctx->text.s.left = ctx->text.s.right = ctx->text.insertPos;   
  2075.     else {
  2076.       ctx->text.origSel.left = ctx->text.s.left;
  2077.       ctx->text.origSel.right = ctx->text.s.right;
  2078.     }
  2079.       
  2080.     ctx->text.origSel.type = ctx->text.s.type;
  2081.  
  2082.     if (pos >= ctx->text.s.left + ((ctx->text.s.right - ctx->text.s.left) / 2))
  2083.     ctx->text.extendDir = XawsdRight;
  2084.     else
  2085.     ctx->text.extendDir = XawsdLeft;
  2086.   }
  2087.   else /* check for change in extend direction */
  2088.     if ((ctx->text.extendDir == XawsdRight && pos <= ctx->text.origSel.left) ||
  2089.     (ctx->text.extendDir == XawsdLeft && pos >= ctx->text.origSel.right)) {
  2090.       ctx->text.extendDir = (ctx->text.extendDir == XawsdRight) ?
  2091.                                                 XawsdLeft : XawsdRight;
  2092.       ModifySelection(ctx, ctx->text.origSel.left, ctx->text.origSel.right);
  2093.     }
  2094.  
  2095.   dir = ctx->text.extendDir;
  2096.   switch (ctx->text.s.type) {
  2097.   case XawselectWord: 
  2098.   case XawselectParagraph:
  2099.     {
  2100.       XawTextPosition left_pos, right_pos;
  2101.       XawTextScanType stype;
  2102.  
  2103.       if (ctx->text.s.type == XawselectWord)
  2104.         stype = XawstWhiteSpace;
  2105.       else
  2106.     stype = XawstParagraph;
  2107.  
  2108.       /*
  2109.        * Somewhat complicated, but basically I treat the space between
  2110.        * two objects as another object.  The object that I am currently
  2111.        * in then becomes the end of the selection.
  2112.        * 
  2113.        * Chris Peterson - 4/19/90.
  2114.        */
  2115.  
  2116.       right_pos = SrcScan(ctx->text.source, pos, stype, XawsdRight, 1, FALSE);
  2117.       right_pos =SrcScan(ctx->text.source, right_pos,stype,XawsdLeft,1, FALSE);
  2118.  
  2119.       if (pos != right_pos) 
  2120.     left_pos = SrcScan(ctx->text.source, pos, stype, XawsdLeft, 1, FALSE);
  2121.       else
  2122.     left_pos = pos;
  2123.  
  2124.       left_pos =SrcScan(ctx->text.source, left_pos, stype, XawsdRight,1,FALSE);
  2125.  
  2126.       if (dir == XawsdLeft)
  2127.     pos = Min(left_pos, right_pos);
  2128.       else /* dir == XawsdRight */
  2129.     pos = Max(left_pos, right_pos);
  2130.     }
  2131.     break;
  2132.   case XawselectLine:
  2133.     pos = SrcScan(ctx->text.source, pos, XawstEOL, dir, 1, dir == XawsdRight);
  2134.     break;
  2135.   case XawselectAll: 
  2136.     pos = ctx->text.insertPos;
  2137.   case XawselectPosition:    /* fall through. */
  2138.   default:
  2139.     break;
  2140.   }
  2141.   
  2142.   if (dir == XawsdRight)
  2143.     ModifySelection(ctx, ctx->text.s.left, pos);
  2144.   else
  2145.     ModifySelection(ctx, pos, ctx->text.s.right);
  2146.  
  2147.   ctx->text.insertPos = pos;
  2148. }
  2149.  
  2150. /*
  2151.  * Clear the window to background color.
  2152.  */
  2153.  
  2154. static void
  2155. ClearWindow (w)
  2156. Widget w;
  2157. {
  2158.   TextWidget ctx = (TextWidget) w;
  2159.  
  2160.   if (XtIsRealized(w))
  2161.     SinkClearToBG(ctx->text.sink, 
  2162.           (Position) 0, (Position) 0, 
  2163.           w->core.width, w->core.height);
  2164. }
  2165.  
  2166. /*    Function Name: _XawTextClearAndCenterDisplay
  2167.  *    Description: Redraws the display with the cursor in insert point
  2168.  *                   centered vertically.
  2169.  *    Arguments: ctx - the text widget.
  2170.  *    Returns: none.
  2171.  */
  2172.  
  2173. void
  2174. _XawTextClearAndCenterDisplay(ctx)
  2175. TextWidget ctx;
  2176. {
  2177.   int insert_line = LineForPosition(ctx, ctx->text.insertPos);
  2178.   int scroll_by = insert_line - ctx->text.lt.lines/2;
  2179.  
  2180.   _XawTextVScroll(ctx, scroll_by);
  2181.   DisplayTextWindow( (Widget) ctx);
  2182. }
  2183.   
  2184. /*
  2185.  * Internal redisplay entire window.
  2186.  * Legal to call only if widget is realized.
  2187.  */
  2188.  
  2189. static void
  2190. DisplayTextWindow (w)
  2191. Widget w;
  2192. {
  2193.   TextWidget ctx = (TextWidget) w;
  2194.   ClearWindow(w);
  2195.   _XawTextBuildLineTable(ctx, ctx->text.lt.top, FALSE);
  2196.   _XawTextNeedsUpdating(ctx, zeroPosition, ctx->text.lastPos);
  2197.   _XawTextSetScrollBars(ctx);
  2198. }
  2199.  
  2200. /*
  2201.  * This routine checks to see if the window should be resized (grown or
  2202.  * shrunk) when text to be painted overflows to the right or
  2203.  * the bottom of the window. It is used by the keyboard input routine.
  2204.  */
  2205.  
  2206. void
  2207. _XawTextCheckResize(ctx)
  2208. TextWidget ctx;
  2209. {
  2210.   Widget w = (Widget) ctx;
  2211.   int line = 0, old_height;
  2212.   XtWidgetGeometry rbox, return_geom;
  2213.  
  2214.   if ( (ctx->text.resize == XawtextResizeWidth) ||
  2215.        (ctx->text.resize == XawtextResizeBoth) ) {
  2216.     XawTextLineTableEntry *lt;
  2217.     rbox.width = 0;
  2218.     for (lt = ctx->text.lt.info; 
  2219.      IsValidLine(ctx, line) && (line < ctx->text.lt.lines);
  2220.      line++, lt++) {
  2221.       if ((int)(lt->textWidth + ctx->text.margin.left) > (int)rbox.width)
  2222.       rbox.width = lt->textWidth + ctx->text.margin.left;
  2223.     }
  2224.     
  2225.     rbox.width += ctx->text.margin.right;
  2226.     if (rbox.width > ctx->core.width) { /* Only get wider. */
  2227.       rbox.request_mode = CWWidth;
  2228.       if (XtMakeGeometryRequest(w, &rbox, &return_geom) == XtGeometryAlmost)
  2229.     (void) XtMakeGeometryRequest(w, &return_geom, NULL);
  2230.     }
  2231.   }
  2232.  
  2233.   if ( !((ctx->text.resize == XawtextResizeHeight) ||
  2234.      (ctx->text.resize == XawtextResizeBoth)) )
  2235.       return;
  2236.  
  2237.   if (IsPositionVisible(ctx, ctx->text.lastPos))
  2238.     line = LineForPosition(ctx, ctx->text.lastPos);
  2239.   else
  2240.     line = ctx->text.lt.lines;
  2241.   
  2242.   if ( (line + 1) == ctx->text.lt.lines ) return;
  2243.   
  2244.   old_height = ctx->core.height;
  2245.   rbox.request_mode = CWHeight;
  2246.   rbox.height = XawTextSinkMaxHeight(ctx->text.sink, line + 1) + VMargins(ctx);
  2247.   
  2248.   if ((int)rbox.height < old_height) return; /* It will only get taller. */
  2249.  
  2250.   if (XtMakeGeometryRequest(w, &rbox, &return_geom) == XtGeometryAlmost)
  2251.     if (XtMakeGeometryRequest(w, &return_geom, NULL) != XtGeometryYes)
  2252.       return;
  2253.   
  2254.   _XawTextBuildLineTable(ctx, ctx->text.lt.top, TRUE);
  2255. }
  2256.  
  2257. /*
  2258.  * Converts (params, num_params) to a list of atoms & caches the
  2259.  * list in the TextWidget instance.
  2260.  */
  2261.  
  2262. Atom*
  2263. _XawTextSelectionList(ctx, list, nelems)
  2264. TextWidget ctx;
  2265. String *list;
  2266. Cardinal nelems;
  2267. {
  2268.   Atom * sel = ctx->text.s.selections;
  2269.   Display *dpy = XtDisplay((Widget) ctx);
  2270.   int n;
  2271.  
  2272.   if (nelems > ctx->text.s.array_size) {
  2273.     sel = (Atom *) XtRealloc((char *) sel, sizeof(Atom) * nelems);
  2274.     ctx->text.s.array_size = nelems;
  2275.     ctx->text.s.selections = sel;
  2276.   }
  2277.   for (n=nelems; --n >= 0; sel++, list++)
  2278.     *sel = XInternAtom(dpy, *list, False);
  2279.   ctx->text.s.atom_count = nelems;
  2280.   return ctx->text.s.selections;
  2281. }
  2282.  
  2283. /*    Function Name: SetSelection
  2284.  *    Description: Sets the current selection.
  2285.  *    Arguments: ctx - the text widget.
  2286.  *                 defaultSel - the default selection.
  2287.  *                 l, r - the left and right ends of the selection.
  2288.  *                 list, nelems - the selection list (as strings).
  2289.  *    Returns: none.
  2290.  *
  2291.  *  NOTE: if (ctx->text.s.left >= ctx->text.s.right) then the selection
  2292.  *        is unset.
  2293.  */
  2294.  
  2295. void
  2296. _XawTextSetSelection(ctx, l, r, list, nelems)
  2297. TextWidget ctx;
  2298. XawTextPosition l, r;
  2299. String *list;
  2300. Cardinal nelems;
  2301. {
  2302.   if (nelems == 1 && !strcmp (list[0], "none"))
  2303.     return;
  2304.   if (nelems == 0) {
  2305.     String defaultSel = "PRIMARY";
  2306.     list = &defaultSel;
  2307.     nelems = 1;
  2308.   }
  2309.   _SetSelection(ctx, l, r, _XawTextSelectionList(ctx, list, nelems), nelems);
  2310. }
  2311.  
  2312.  
  2313. /*    Function Name: ModifySelection
  2314.  *    Description: Modifies the current selection.
  2315.  *    Arguments: ctx - the text widget.
  2316.  *                 left, right - the left and right ends of the selection.
  2317.  *    Returns: none.
  2318.  *
  2319.  *  NOTE: if (ctx->text.s.left >= ctx->text.s.right) then the selection
  2320.  *        is unset.
  2321.  */
  2322.  
  2323. static void
  2324. ModifySelection(ctx, left, right)
  2325. TextWidget ctx;
  2326. XawTextPosition left, right;
  2327. {
  2328.   if (left == right) 
  2329.     ctx->text.insertPos = left;
  2330.   _SetSelection( ctx, left, right, NULL, ZERO);
  2331. }
  2332.  
  2333. /*
  2334.  * This routine is used to perform various selection functions. The goal is
  2335.  * to be able to specify all the more popular forms of draw-through and
  2336.  * multi-click selection user interfaces from the outside.
  2337.  */
  2338.  
  2339. void 
  2340. _XawTextAlterSelection (ctx, mode, action, params, num_params)
  2341. TextWidget ctx;
  2342. XawTextSelectionMode mode;   /* {XawsmTextSelect, XawsmTextExtend} */
  2343. XawTextSelectionAction action; /* {XawactionStart, 
  2344.                   XawactionAdjust, XawactionEnd} */
  2345. String    *params;
  2346. Cardinal    *num_params;
  2347. {
  2348.   XawTextPosition position;
  2349.   Boolean flag;
  2350.  
  2351. /*
  2352.  * This flag is used by TextPop.c:DoReplace() to determine if the selection
  2353.  * is okay to use, or if it has been modified.
  2354.  */
  2355.     
  2356.   if (ctx->text.search != NULL)
  2357.     ctx->text.search->selection_changed = TRUE;
  2358.  
  2359.   position = PositionForXY (ctx, (int) ctx->text.ev_x, (int) ctx->text.ev_y);
  2360.  
  2361.   flag = (action != XawactionStart);
  2362.   if (mode == XawsmTextSelect)
  2363.     DoSelection (ctx, position, ctx->text.time, flag);
  2364.   else            /* mode == XawsmTextExtend */
  2365.    ExtendSelection (ctx, position, flag);
  2366.  
  2367.   if (action == XawactionEnd) 
  2368.     _XawTextSetSelection(ctx, ctx->text.s.left, ctx->text.s.right,
  2369.              params, *num_params);
  2370. }
  2371.  
  2372. /*    Function Name: RectanglesOverlap
  2373.  *    Description: Returns TRUE if two rectangles overlap.
  2374.  *    Arguments: rect1, rect2 - the two rectangles to check.
  2375.  *    Returns: TRUE iff these rectangles overlap.
  2376.  */
  2377.  
  2378. static Boolean
  2379. RectanglesOverlap(rect1, rect2)
  2380. XRectangle *rect1, *rect2;
  2381. {
  2382.   return ( (rect1->x < rect2->x + (short) rect2->width) &&
  2383.        (rect2->x < rect1->x + (short) rect1->width) &&
  2384.        (rect1->y < rect2->y + (short) rect2->height) &&
  2385.        (rect2->y < rect1->y + (short) rect1->height) );
  2386. }
  2387.  
  2388. /*    Function Name: UpdateTextInRectangle.
  2389.  *    Description: Updates the text in a rectangle.
  2390.  *    Arguments: ctx - the text widget.
  2391.  *                 rect - the rectangle to update.
  2392.  *    Returns: none.
  2393.  */
  2394.  
  2395. static void
  2396. UpdateTextInRectangle(ctx, rect)
  2397. TextWidget ctx;
  2398. XRectangle * rect;
  2399. {
  2400.   XawTextLineTableEntry *info = ctx->text.lt.info;
  2401.   int line, x = rect->x, y = rect->y;
  2402.   int right = rect->width + x, bottom = rect->height + y;
  2403.  
  2404.   for (line = 0;( (line < ctx->text.lt.lines) &&
  2405.          IsValidLine(ctx, line) && (info->y < bottom)); line++, info++)
  2406.     if ( (info + 1)->y >= y ) 
  2407.       UpdateTextInLine(ctx, line, x, right);
  2408. }
  2409.  
  2410. /*
  2411.  * This routine processes all "expose region" XEvents. In general, its job
  2412.  * is to the best job at minimal re-paint of the text, displayed in the
  2413.  * window, that it can.
  2414.  */
  2415.  
  2416. /* ARGSUSED */
  2417. static void
  2418. ProcessExposeRegion(w, event, region)
  2419. Widget w;
  2420. XEvent *event;
  2421. Region region;            /* Unused. */
  2422. {
  2423.     TextWidget ctx = (TextWidget) w;
  2424.     XRectangle expose, cursor;
  2425.     Boolean need_to_draw;
  2426.     
  2427.     if (event->type == Expose) {
  2428.     expose.x = event->xexpose.x;
  2429.     expose.y = event->xexpose.y;
  2430.     expose.width = event->xexpose.width;
  2431.     expose.height = event->xexpose.height;
  2432.     }
  2433.     else if (event->type == GraphicsExpose) {
  2434.     expose.x = event->xgraphicsexpose.x;
  2435.     expose.y = event->xgraphicsexpose.y;
  2436.     expose.width = event->xgraphicsexpose.width;
  2437.     expose.height = event->xgraphicsexpose.height;
  2438.     }      
  2439.     else { /* No Expose */
  2440.     PopCopyQueue(ctx);        
  2441.     return;            /* no more processing necessary. */
  2442.     }
  2443.  
  2444.     need_to_draw = TranslateExposeRegion(ctx, &expose);
  2445.     if ((event->type == GraphicsExpose) && (event->xgraphicsexpose.count == 0))
  2446.     PopCopyQueue(ctx);    
  2447.  
  2448.     if (!need_to_draw) 
  2449.     return;            /* don't draw if we don't need to. */
  2450.  
  2451.     _XawTextPrepareToUpdate(ctx);
  2452.     UpdateTextInRectangle(ctx, &expose);
  2453.     XawTextSinkGetCursorBounds(ctx->text.sink, &cursor);
  2454.     if (RectanglesOverlap(&cursor, &expose)) {
  2455.     SinkClearToBG(ctx->text.sink, (Position) cursor.x, (Position) cursor.y,
  2456.               (Dimension) cursor.width, (Dimension) cursor.height);
  2457.     UpdateTextInRectangle(ctx, &cursor);
  2458.     }
  2459.     _XawTextExecuteUpdate(ctx);
  2460. }
  2461.  
  2462. /*
  2463.  * This routine does all setup required to syncronize batched screen updates
  2464.  */
  2465.  
  2466. _XawTextPrepareToUpdate(ctx)
  2467. TextWidget ctx;
  2468. {
  2469.   if (ctx->text.old_insert < 0) {
  2470.     InsertCursor((Widget)ctx, XawisOff);
  2471.     ctx->text.numranges = 0;
  2472.     ctx->text.showposition = FALSE;
  2473.     ctx->text.old_insert = ctx->text.insertPos;
  2474.   }
  2475. }
  2476.  
  2477. /*
  2478.  * This is a private utility routine used by _XawTextExecuteUpdate. It
  2479.  * processes all the outstanding update requests and merges update
  2480.  * ranges where possible.
  2481.  */
  2482.  
  2483. static 
  2484. void FlushUpdate(ctx)
  2485. TextWidget ctx;
  2486. {
  2487.   int i, w;
  2488.   XawTextPosition updateFrom, updateTo;
  2489.   if (!XtIsRealized((Widget)ctx)) {
  2490.     ctx->text.numranges = 0;
  2491.     return;
  2492.   }
  2493.   while (ctx->text.numranges > 0) {
  2494.     updateFrom = ctx->text.updateFrom[0];
  2495.     w = 0;
  2496.     for (i = 1 ; i < ctx->text.numranges ; i++) {
  2497.       if (ctx->text.updateFrom[i] < updateFrom) {
  2498.     updateFrom = ctx->text.updateFrom[i];
  2499.     w = i;
  2500.       }
  2501.     }
  2502.     updateTo = ctx->text.updateTo[w];
  2503.     ctx->text.numranges--;
  2504.     ctx->text.updateFrom[w] = ctx->text.updateFrom[ctx->text.numranges];
  2505.     ctx->text.updateTo[w] = ctx->text.updateTo[ctx->text.numranges];
  2506.     for (i = ctx->text.numranges - 1 ; i >= 0 ; i--) {
  2507.       while (ctx->text.updateFrom[i] <= updateTo && i < ctx->text.numranges) {
  2508.     updateTo = ctx->text.updateTo[i];
  2509.     ctx->text.numranges--;
  2510.     ctx->text.updateFrom[i] = ctx->text.updateFrom[ctx->text.numranges];
  2511.     ctx->text.updateTo[i] = ctx->text.updateTo[ctx->text.numranges];
  2512.       }
  2513.     }
  2514.     DisplayText((Widget)ctx, updateFrom, updateTo);
  2515.   }
  2516. }
  2517.  
  2518. /*
  2519.  * This is a private utility routine used by _XawTextExecuteUpdate. This
  2520.  * routine worries about edits causing new data or the insertion point becoming
  2521.  * invisible (off the screen, or under the horiz. scrollbar). Currently 
  2522.  * it always makes it visible by scrolling. It probably needs 
  2523.  * generalization to allow more options.
  2524.  */
  2525.  
  2526. _XawTextShowPosition(ctx)
  2527. TextWidget ctx;
  2528. {
  2529.   int x, y, lines, number;
  2530.   Boolean no_scroll;
  2531.   XawTextPosition max_pos, top, first;
  2532.  
  2533.   if ( (!XtIsRealized((Widget)ctx)) || (ctx->text.lt.lines <= 0) )
  2534.     return;
  2535.  
  2536. /*
  2537.  * Find out the bottom the visable window, and make sure that the
  2538.  * cursor does not go past the end of this space.  
  2539.  *
  2540.  * This makes sure that the cursor does not go past the end of the 
  2541.  * visable window. 
  2542.  */
  2543.  
  2544.   x = ctx->core.width;
  2545.   y = ctx->core.height - ctx->text.margin.bottom;
  2546.   if (ctx->text.hbar != NULL)
  2547.     y -= ctx->text.hbar->core.height + 2 * ctx->text.hbar->core.border_width;
  2548.   
  2549.   max_pos = PositionForXY (ctx, x, y);
  2550.   lines = LineForPosition(ctx, max_pos) + 1; /* number of visable lines. */
  2551.   
  2552.   if ( (ctx->text.insertPos >= ctx->text.lt.top) &&
  2553.        (ctx->text.insertPos < max_pos))
  2554.     return;
  2555.  
  2556.   first = ctx->text.lt.top;
  2557.   no_scroll = FALSE;
  2558.  
  2559.   if (ctx->text.insertPos < first) { /* We need to scroll down. */
  2560.       top = SrcScan(ctx->text.source, ctx->text.insertPos,
  2561.             XawstEOL, XawsdLeft, 1, FALSE);
  2562.  
  2563.       /* count the number of lines we have to scroll */
  2564.  
  2565.       number = 0;
  2566.       while (first > top) {
  2567.       first = SrcScan(ctx->text.source, first,
  2568.               XawstEOL, XawsdLeft, 1, TRUE);
  2569.  
  2570.       if ( - number > lines ) 
  2571.           break;
  2572.  
  2573.       number--;
  2574.       }
  2575.  
  2576.       if (first <= top) {    /* If we found the proper number
  2577.                    of lines. */
  2578.      
  2579.       /* Back up to just before the last CR. */
  2580.       
  2581.       first = SrcScan(ctx->text.source, first,
  2582.               XawstPositions, XawsdRight, 1, TRUE);
  2583.       
  2584.       /* Check to make sure the cursor is visable. */
  2585.       
  2586.       if (first <= top)
  2587.           number++;
  2588.       
  2589.       lines = number;
  2590.       }
  2591.       else
  2592.       no_scroll = TRUE;
  2593.   }
  2594.   else {            /* We need to Scroll up */
  2595.       top = SrcScan(ctx->text.source, ctx->text.insertPos,
  2596.             XawstEOL, XawsdLeft, lines, FALSE);
  2597.  
  2598.       if (top < max_pos) 
  2599.       lines = LineForPosition(ctx, top);
  2600.       else 
  2601.       no_scroll = TRUE;
  2602.   }
  2603.  
  2604.   if (no_scroll) {
  2605.       _XawTextBuildLineTable(ctx, top, FALSE);      
  2606.       DisplayTextWindow((Widget)ctx);
  2607.   }
  2608.   else 
  2609.       _XawTextVScroll(ctx, lines);
  2610.  
  2611.   _XawTextSetScrollBars(ctx);
  2612. }
  2613.  
  2614. /*
  2615.  * This routine causes all batched screen updates to be performed
  2616.  */
  2617.  
  2618. void
  2619. _XawTextExecuteUpdate(ctx)
  2620. TextWidget ctx;
  2621. {
  2622.   if ( ctx->text.update_disabled || (ctx->text.old_insert < 0) ) 
  2623.     return;
  2624.  
  2625.   if((ctx->text.old_insert != ctx->text.insertPos) || (ctx->text.showposition))
  2626.     _XawTextShowPosition(ctx);
  2627.   FlushUpdate(ctx);
  2628.   InsertCursor((Widget)ctx, XawisOn);
  2629.   ctx->text.old_insert = -1;
  2630. }
  2631.  
  2632.  
  2633. static void 
  2634. TextDestroy(w)
  2635. Widget w;
  2636. {
  2637.   TextWidget ctx = (TextWidget)w;
  2638.  
  2639.   DestroyHScrollBar(ctx);
  2640.   DestroyVScrollBar(ctx);
  2641.  
  2642.   XtFree((char *)ctx->text.s.selections);
  2643.   XtFree((char *)ctx->text.lt.info);
  2644.   XtFree((char *)ctx->text.search);
  2645.   XtFree((char *)ctx->text.updateFrom);
  2646.   XtFree((char *)ctx->text.updateTo);
  2647. }
  2648.  
  2649. /*
  2650.  * by the time we are managed (and get this far) we had better
  2651.  * have both a source and a sink 
  2652.  */
  2653.  
  2654. static void
  2655. Resize(w)
  2656. Widget w;
  2657. {
  2658.   TextWidget ctx = (TextWidget) w;
  2659.  
  2660.   PositionVScrollBar(ctx);
  2661.   PositionHScrollBar(ctx);
  2662.  
  2663.   _XawTextBuildLineTable(ctx, ctx->text.lt.top, TRUE);
  2664.   _XawTextSetScrollBars(ctx);
  2665. }
  2666.  
  2667. /*
  2668.  * This routine allow the application program to Set attributes.
  2669.  */
  2670.  
  2671. /*ARGSUSED*/
  2672. static Boolean 
  2673. SetValues(current, request, new, args, num_args)
  2674. Widget current, request, new;
  2675. ArgList args;
  2676. Cardinal *num_args;
  2677. {
  2678.   TextWidget oldtw = (TextWidget) current;
  2679.   TextWidget newtw = (TextWidget) new;
  2680.   Boolean    redisplay = FALSE;
  2681.   Boolean    display_caret = newtw->text.display_caret;
  2682.  
  2683.  
  2684.   newtw->text.display_caret = oldtw->text.display_caret;
  2685.   _XawTextPrepareToUpdate(newtw);
  2686.   newtw->text.display_caret = display_caret;
  2687.  
  2688.   if (oldtw->text.r_margin.left != newtw->text.r_margin.left) {
  2689.     newtw->text.margin.left = newtw->text.r_margin.left;
  2690.     if (newtw->text.vbar != NULL)
  2691.       newtw->text.margin.left += newtw->text.vbar->core.width +
  2692.                              newtw->text.vbar->core.border_width;
  2693.     redisplay = TRUE;
  2694.   }
  2695.   
  2696.   if (oldtw->text.scroll_vert != newtw->text.scroll_vert) {
  2697.     if (newtw->text.scroll_vert == XawtextScrollNever) 
  2698.       DestroyVScrollBar(newtw);
  2699.     else if (newtw->text.scroll_vert == XawtextScrollAlways)
  2700.       CreateVScrollBar(newtw);
  2701.     redisplay = TRUE;
  2702.   }
  2703.  
  2704.   if (oldtw->text.r_margin.bottom != newtw->text.r_margin.bottom) {
  2705.     newtw->text.margin.bottom = newtw->text.r_margin.bottom;
  2706.     if (newtw->text.hbar != NULL)
  2707.       newtw->text.margin.bottom += newtw->text.hbar->core.height +
  2708.                                newtw->text.hbar->core.border_width;
  2709.     redisplay = TRUE;
  2710.   }
  2711.   
  2712.   if (oldtw->text.scroll_horiz != newtw->text.scroll_horiz) {
  2713.     if (newtw->text.scroll_horiz == XawtextScrollNever) 
  2714.       DestroyHScrollBar(newtw);
  2715.     else if (newtw->text.scroll_horiz == XawtextScrollAlways)
  2716.       CreateHScrollBar(newtw);
  2717.     redisplay = TRUE;
  2718.   }
  2719.  
  2720.   if ( oldtw->text.source != newtw->text.source )
  2721.     XawTextSetSource( (Widget) newtw, newtw->text.source, newtw->text.lt.top);
  2722.  
  2723.   newtw->text.redisplay_needed = False;
  2724.   XtSetValues( (Widget)newtw->text.source, args, *num_args );
  2725.   XtSetValues( (Widget)newtw->text.sink, args, *num_args );
  2726.  
  2727.   if ( oldtw->text.wrap != newtw->text.wrap ||
  2728.        oldtw->text.lt.top != newtw->text.lt.top ||
  2729.        oldtw->text.r_margin.right != newtw->text.r_margin.right ||
  2730.        oldtw->text.r_margin.top != newtw->text.r_margin.top ||
  2731.        oldtw->text.sink != newtw->text.sink ||
  2732.        newtw->text.redisplay_needed )
  2733.   {
  2734.     _XawTextBuildLineTable(newtw, newtw->text.lt.top, TRUE);
  2735.     redisplay = TRUE;
  2736.   }
  2737.  
  2738.   if (oldtw->text.insertPos != newtw->text.insertPos) {
  2739.     newtw->text.showposition = TRUE;
  2740.     redisplay = TRUE;
  2741.   }
  2742.  
  2743.   _XawTextExecuteUpdate(newtw);
  2744.   if (redisplay)
  2745.     _XawTextSetScrollBars(newtw);
  2746.  
  2747.   return redisplay;
  2748. }
  2749.  
  2750. /* invoked by the Simple widget's SetValues */
  2751. static Boolean ChangeSensitive(w)
  2752.     Widget w;    /* the new widget */
  2753. {
  2754.     Arg args[1];
  2755.     TextWidget tw = (TextWidget) w;
  2756.  
  2757.     (*(&simpleClassRec)->simple_class.change_sensitive)(w);
  2758.  
  2759.     XtSetArg(args[0], XtNancestorSensitive, 
  2760.            (tw->core.ancestor_sensitive && tw->core.sensitive));
  2761.     if (tw->text.vbar)
  2762.     XtSetValues(tw->text.vbar, args, ONE);
  2763.     if (tw->text.hbar)
  2764.     XtSetValues(tw->text.hbar, args, ONE);
  2765.     return False;
  2766. }
  2767.  
  2768. /*    Function Name: GetValuesHook
  2769.  *    Description: This is a get values hook routine that gets the
  2770.  *                   values in the text source and sink.
  2771.  *    Arguments: w - the Text Widget.
  2772.  *                 args - the argument list.
  2773.  *                 num_args - the number of args.
  2774.  *    Returns: none.
  2775.  */
  2776.  
  2777. static void
  2778. GetValuesHook(w, args, num_args)
  2779. Widget w;
  2780. ArgList args;
  2781. Cardinal * num_args;
  2782. {
  2783.   XtGetValues( ((TextWidget) w)->text.source, args, *num_args );
  2784.   XtGetValues( ((TextWidget) w)->text.sink, args, *num_args );
  2785. }
  2786.  
  2787. /*    Function Name: FindGoodPosition
  2788.  *    Description: Returns a valid position given any postition
  2789.  *    Arguments: pos - any position.
  2790.  *    Returns: a position between (0 and lastPos);
  2791.  */
  2792.  
  2793. static XawTextPosition
  2794. FindGoodPosition(ctx, pos)
  2795. TextWidget ctx;
  2796. XawTextPosition pos;
  2797. {
  2798.   if (pos < 0) return(0);
  2799.   return ( ((pos > ctx->text.lastPos) ? ctx->text.lastPos : pos) );
  2800. }
  2801.  
  2802. /************************************************************
  2803.  * 
  2804.  * Routines for handling the copy area expose queue.
  2805.  *
  2806.  ************************************************************/
  2807.  
  2808. /*    Function Name: PushCopyQueue
  2809.  *    Description: Pushes a value onto the copy queue.
  2810.  *    Arguments: ctx - the text widget.
  2811.  *                 h, v - amount of offset in the horiz and vert directions.
  2812.  *    Returns: none
  2813.  */
  2814.  
  2815. static void
  2816. PushCopyQueue(ctx, h, v)
  2817. TextWidget ctx;
  2818. int h, v;
  2819. {
  2820.     struct text_move * offsets = XtNew(struct text_move);
  2821.  
  2822.     offsets->h = h;
  2823.     offsets->v = v;
  2824.     offsets->next = NULL;
  2825.  
  2826.     if (ctx->text.copy_area_offsets == NULL)
  2827.     ctx->text.copy_area_offsets = offsets;
  2828.     else {
  2829.     struct text_move * end = ctx->text.copy_area_offsets;
  2830.     for ( ; end->next != NULL; end = end->next) {}
  2831.     end->next = offsets;
  2832.     }
  2833. }
  2834.  
  2835. /*    Function Name: PopCopyQueue
  2836.  *    Description: Pops the top value off of the copy queue.
  2837.  *    Arguments: ctx - the text widget.
  2838.  *    Returns: none.
  2839.  */
  2840.  
  2841. static void
  2842. PopCopyQueue(ctx)
  2843. TextWidget ctx;
  2844. {
  2845.     struct text_move * offsets = ctx->text.copy_area_offsets;
  2846.  
  2847.     if (offsets == NULL)
  2848.     printf("empty copy queue\n");
  2849.     else {
  2850.     ctx->text.copy_area_offsets = offsets->next;
  2851.     XtFree((char *) offsets);    /* free what you allocate. */
  2852.     }
  2853. }
  2854.  
  2855. /*    Function Name:  TranslateExposeRegion
  2856.  *    Description: Translates the expose that came into
  2857.  *                   the cordinates that now exist in the Text widget.
  2858.  *    Arguments: ctx - the text widget.
  2859.  *                 expose - a Rectangle, who's region currently
  2860.  *                          contains the expose event location.
  2861.  *                          this region will be returned containing
  2862.  *                          the new rectangle.
  2863.  *    Returns: True if there is drawing that needs to be done.
  2864.  */
  2865.  
  2866. static Boolean
  2867. TranslateExposeRegion(ctx, expose)
  2868. TextWidget ctx;
  2869. XRectangle * expose;
  2870. {
  2871.     struct text_move * offsets = ctx->text.copy_area_offsets;
  2872.     int value;
  2873.     int x, y, width, height;
  2874.  
  2875.     /*
  2876.      * Skip over the first one, this has already been taken into account.
  2877.      */
  2878.  
  2879.     if (!offsets || !(offsets = offsets->next))
  2880.     return(TRUE);
  2881.  
  2882.     x = expose->x;
  2883.     y = expose->y;
  2884.     width = expose->width;
  2885.     height = expose->height;
  2886.  
  2887.     while (offsets) {
  2888.     x += offsets->h;
  2889.     y += offsets->v;
  2890.     offsets = offsets->next;
  2891.     }
  2892.  
  2893.     /*
  2894.      * remove that area of the region that is now outside the window.
  2895.      */
  2896.  
  2897.     if (y < 0) {
  2898.     height += y;
  2899.     y = 0;
  2900.     }
  2901.  
  2902.     value = y + height - ctx->core.height;
  2903.     if (value > 0)
  2904.     height -= value;
  2905.  
  2906.     if (height <= 0)
  2907.     return(FALSE);        /* no need to draw outside the window. */
  2908.  
  2909.     /*
  2910.      * and now in the horiz direction...
  2911.      */
  2912.  
  2913.     if (x < 0) {
  2914.     width += x;
  2915.     x = 0;
  2916.     }
  2917.  
  2918.     value = x + width - ctx->core.width;
  2919.     if (value > 0)
  2920.     width -= value;
  2921.  
  2922.     if (width <= 0)
  2923.     return(FALSE);        /* no need to draw outside the window. */
  2924.     
  2925.     expose->x = x;
  2926.     expose->y = y;
  2927.     expose->width = width;
  2928.     expose->height = height;
  2929.     return(TRUE);
  2930. }
  2931.  
  2932. /*******************************************************************
  2933. The following routines provide procedural interfaces to Text window state
  2934. setting and getting. They need to be redone so than the args code can use
  2935. them. I suggest we create a complete set that takes the context as an
  2936. argument and then have the public version lookp the context and call the
  2937. internal one. The major value of this set is that they have actual application
  2938. clients and therefore the functionality provided is required for any future
  2939. version of Text.
  2940. ********************************************************************/
  2941.  
  2942. void
  2943. #if NeedFunctionPrototypes
  2944. XawTextDisplay (Widget w)
  2945. #else
  2946. XawTextDisplay (w)
  2947. Widget w;
  2948. #endif
  2949. {
  2950.   if (!XtIsRealized(w)) return;
  2951.   
  2952.   _XawTextPrepareToUpdate( (TextWidget) w);
  2953.   DisplayTextWindow(w);
  2954.   _XawTextExecuteUpdate( (TextWidget) w);
  2955. }
  2956.  
  2957. void
  2958. #if NeedFunctionPrototypes
  2959. XawTextSetSelectionArray(Widget w, XawTextSelectType *sarray)
  2960. #else
  2961. XawTextSetSelectionArray(w, sarray)
  2962. Widget w;
  2963. XawTextSelectType *sarray;
  2964. #endif
  2965. {
  2966.   ((TextWidget)w)->text.sarray = sarray;
  2967. }
  2968.  
  2969. void
  2970. #if NeedFunctionPrototypes
  2971. XawTextGetSelectionPos(Widget w, XawTextPosition *left, XawTextPosition *right)
  2972. #else
  2973. XawTextGetSelectionPos(w, left, right)
  2974. Widget w;
  2975. XawTextPosition *left, *right;
  2976. #endif
  2977. {
  2978.   *left = ((TextWidget) w)->text.s.left;
  2979.   *right = ((TextWidget) w)->text.s.right;
  2980. }
  2981.  
  2982.  
  2983. void 
  2984. #if NeedFunctionPrototypes
  2985. XawTextSetSource(Widget w, Widget source, XawTextPosition startPos)
  2986. #else
  2987. XawTextSetSource(w, source, startPos)
  2988. Widget w, source;
  2989. XawTextPosition startPos;
  2990. #endif
  2991. {
  2992.   TextWidget ctx = (TextWidget) w;
  2993.  
  2994.   ctx->text.source = source;
  2995.   ctx->text.lt.top = startPos;
  2996.   ctx->text.s.left = ctx->text.s.right = 0;
  2997.   ctx->text.insertPos = startPos;
  2998.   ctx->text.lastPos = GETLASTPOS;
  2999.   
  3000.   _XawTextBuildLineTable(ctx, ctx->text.lt.top, TRUE);
  3001.   XawTextDisplay(w);
  3002. }
  3003.  
  3004. /*
  3005.  * This public routine deletes the text from startPos to endPos in a source and
  3006.  * then inserts, at startPos, the text that was passed. As a side effect it
  3007.  * "invalidates" that portion of the displayed text (if any), so that things
  3008.  * will be repainted properly.
  3009.  */
  3010.  
  3011. int 
  3012. #if NeedFunctionPrototypes
  3013. XawTextReplace(Widget w, XawTextPosition startPos, XawTextPosition endPos,
  3014.            XawTextBlock *text)
  3015. #else
  3016. XawTextReplace(w, startPos, endPos, text)
  3017. Widget w;
  3018. XawTextPosition  startPos, endPos;
  3019. XawTextBlock *text;
  3020. #endif
  3021. {
  3022.   TextWidget ctx = (TextWidget) w;
  3023.   int result;
  3024.  
  3025.   _XawTextPrepareToUpdate(ctx);
  3026.   endPos = FindGoodPosition(ctx, endPos);
  3027.   startPos = FindGoodPosition(ctx, startPos);
  3028.   if ((result = _XawTextReplace(ctx, startPos, endPos, text)) == XawEditDone) {
  3029.     int delta = text->length - (endPos - startPos);
  3030.     if (ctx->text.insertPos >= (endPos + delta)) {
  3031.       XawTextScanDirection sd = (delta < 0) ? XawsdLeft : XawsdRight;
  3032.       ctx->text.insertPos = SrcScan(ctx->text.source, ctx->text.insertPos,
  3033.                     XawstPositions, sd, abs(delta), TRUE);
  3034.     }
  3035.   }
  3036.  
  3037.   _XawTextCheckResize(ctx);
  3038.   _XawTextExecuteUpdate(ctx);
  3039.   _XawTextSetScrollBars(ctx);
  3040.   
  3041.   return result;
  3042. }
  3043.  
  3044. XawTextPosition 
  3045. #if NeedFunctionPrototypes
  3046. XawTextTopPosition(Widget w)
  3047. #else
  3048. XawTextTopPosition(w)
  3049. Widget w;
  3050. #endif
  3051. {
  3052.   return( ((TextWidget) w)->text.lt.top );
  3053. }
  3054.  
  3055. void 
  3056. #if NeedFunctionPrototypes
  3057. XawTextSetInsertionPoint(Widget w, XawTextPosition position)
  3058. #else
  3059. XawTextSetInsertionPoint(w, position)
  3060. Widget w;
  3061. XawTextPosition position;
  3062. #endif
  3063. {
  3064.   TextWidget ctx = (TextWidget) w;
  3065.  
  3066.   _XawTextPrepareToUpdate(ctx);
  3067.   ctx->text.insertPos = FindGoodPosition(ctx, position);
  3068.   ctx->text.showposition = TRUE;
  3069.  
  3070.   _XawTextExecuteUpdate(ctx);
  3071. }
  3072.  
  3073. XawTextPosition
  3074. #if NeedFunctionPrototypes
  3075. XawTextGetInsertionPoint(Widget w)
  3076. #else
  3077. XawTextGetInsertionPoint(w)
  3078. Widget w;
  3079. #endif
  3080. {
  3081.   return( ((TextWidget) w)->text.insertPos);
  3082. }
  3083.  
  3084. /*
  3085.  * NOTE: Must walk the selection list in opposite order from LoseSelection.
  3086.  */
  3087.  
  3088. void 
  3089. #if NeedFunctionPrototypes
  3090. XawTextUnsetSelection(Widget w)
  3091. #else
  3092. XawTextUnsetSelection(w)
  3093. Widget w;
  3094. #endif
  3095. {
  3096.   register TextWidget ctx = (TextWidget)w;
  3097.  
  3098.   while (ctx->text.s.atom_count != 0) {
  3099.     Atom sel = ctx->text.s.selections[ctx->text.s.atom_count - 1];
  3100.     if ( sel != (Atom) 0 ) {
  3101. /*
  3102.  * As selections are lost the atom_count will decrement.
  3103.  */
  3104.       if (GetCutBufferNumber(sel) == NOT_A_CUT_BUFFER)
  3105.     XtDisownSelection(w, sel, ctx->text.time);
  3106.       LoseSelection(w, &sel); /* In case this is a cut buffer, or 
  3107.                  XtDisownSelection failed to call us. */
  3108.     }
  3109.   }
  3110. }
  3111.  
  3112. void
  3113. #if NeedFunctionPrototypes
  3114. XawTextSetSelection (Widget w, XawTextPosition left, XawTextPosition right)
  3115. #else
  3116. XawTextSetSelection (w, left, right)
  3117. Widget w;
  3118. XawTextPosition left, right;
  3119. #endif
  3120. {
  3121.   TextWidget ctx = (TextWidget) w;
  3122.   
  3123.   _XawTextPrepareToUpdate(ctx);
  3124.   _XawTextSetSelection(ctx, FindGoodPosition(ctx, left),
  3125.                FindGoodPosition(ctx, right), NULL, ZERO);
  3126.   _XawTextExecuteUpdate(ctx);
  3127. }
  3128.  
  3129. void 
  3130. #if NeedFunctionPrototypes
  3131. XawTextInvalidate(Widget w, XawTextPosition from, XawTextPosition to)
  3132. #else
  3133. XawTextInvalidate(w, from, to)
  3134. Widget w;
  3135. XawTextPosition from,to;
  3136. #endif
  3137. {
  3138.   TextWidget ctx = (TextWidget) w;
  3139.  
  3140.   from = FindGoodPosition(ctx, from);
  3141.   to = FindGoodPosition(ctx, to);
  3142.   ctx->text.lastPos = GETLASTPOS;
  3143.   _XawTextPrepareToUpdate(ctx);
  3144.   _XawTextNeedsUpdating(ctx, from, to);
  3145.   _XawTextBuildLineTable(ctx, ctx->text.lt.top, TRUE);
  3146.   _XawTextExecuteUpdate(ctx);
  3147. }
  3148.  
  3149. /*ARGSUSED*/
  3150. void
  3151. #if NeedFunctionPrototypes
  3152. XawTextDisableRedisplay(Widget w)
  3153. #else
  3154. XawTextDisableRedisplay(w)
  3155. Widget w;
  3156. #endif
  3157. {
  3158.   ((TextWidget) w)->text.update_disabled = True;
  3159.   _XawTextPrepareToUpdate( (TextWidget) w);
  3160. }
  3161.  
  3162. void 
  3163. #if NeedFunctionPrototypes
  3164. XawTextEnableRedisplay(Widget w)
  3165. #else
  3166. XawTextEnableRedisplay(w)
  3167. Widget w;
  3168. #endif
  3169. {
  3170.   register TextWidget ctx = (TextWidget)w;
  3171.   XawTextPosition lastPos;
  3172.  
  3173.   if (!ctx->text.update_disabled) return;
  3174.  
  3175.   ctx->text.update_disabled = False;
  3176.   lastPos = ctx->text.lastPos = GETLASTPOS;
  3177.   ctx->text.lt.top = FindGoodPosition(ctx, ctx->text.lt.top);
  3178.   ctx->text.insertPos = FindGoodPosition(ctx, ctx->text.insertPos);
  3179.   if ( (ctx->text.s.left > lastPos) || (ctx->text.s.right > lastPos) ) 
  3180.     ctx->text.s.left = ctx->text.s.right = 0;
  3181.   
  3182.   _XawTextBuildLineTable(ctx, ctx->text.lt.top, TRUE);
  3183.   if (XtIsRealized(w))
  3184.     DisplayTextWindow(w);
  3185.   _XawTextExecuteUpdate(ctx);
  3186. }
  3187.  
  3188. Widget
  3189. #if NeedFunctionPrototypes
  3190. XawTextGetSource(Widget w)
  3191. #else
  3192. XawTextGetSource(w)
  3193. Widget w;
  3194. #endif
  3195. {
  3196.   return ((TextWidget)w)->text.source;
  3197. }
  3198.  
  3199. void
  3200. #if NeedFunctionPrototypes
  3201. XawTextDisplayCaret (Widget w,
  3202. #if NeedWidePrototypes
  3203.              /* Boolean */ int display_caret)
  3204. #else
  3205.              Boolean display_caret)
  3206. #endif
  3207. #else
  3208. XawTextDisplayCaret (w, display_caret)
  3209. Widget w;
  3210. Boolean display_caret;
  3211. #endif
  3212. {
  3213.   TextWidget ctx = (TextWidget) w;
  3214.  
  3215.   if (ctx->text.display_caret == display_caret) return;
  3216.  
  3217.   if (XtIsRealized(w)) {
  3218.     _XawTextPrepareToUpdate(ctx);
  3219.     ctx->text.display_caret = display_caret;
  3220.     _XawTextExecuteUpdate(ctx);
  3221.   }
  3222.   else
  3223.     ctx->text.display_caret = display_caret;
  3224. }
  3225.  
  3226. /*    Function Name: XawTextSearch(w, dir, text).
  3227.  *    Description: searches for the given text block.
  3228.  *    Arguments: w - The text widget.
  3229.  *                 dir - The direction to search. 
  3230.  *                 text - The text block containing info about the string
  3231.  *                        to search for.
  3232.  *    Returns: The position of the text found, or XawTextSearchError on 
  3233.  *               an error.
  3234.  */
  3235.  
  3236. XawTextPosition
  3237. #if NeedFunctionPrototypes
  3238. XawTextSearch(Widget w,
  3239. #if NeedWidePrototypes
  3240.           /* XawTextScanDirection */ int dir,
  3241. #else
  3242.           XawTextScanDirection dir,
  3243. #endif
  3244.           XawTextBlock *text)
  3245. #else
  3246. XawTextSearch(w, dir, text) 
  3247. Widget w;
  3248. XawTextScanDirection dir;
  3249. XawTextBlock * text;
  3250. #endif
  3251. {
  3252.   TextWidget ctx = (TextWidget) w;
  3253.  
  3254.   return(SrcSearch(ctx->text.source, ctx->text.insertPos, dir, text));
  3255. }
  3256.   
  3257. TextClassRec textClassRec = {
  3258.   { /* core fields */
  3259.     /* superclass       */      (WidgetClass) &simpleClassRec,
  3260.     /* class_name       */      "Text",
  3261.     /* widget_size      */      sizeof(TextRec),
  3262.     /* class_initialize */      ClassInitialize,
  3263.     /* class_part_init  */    NULL,
  3264.     /* class_inited     */      FALSE,
  3265.     /* initialize       */      Initialize,
  3266.     /* initialize_hook  */    NULL,
  3267.     /* realize          */      Realize,
  3268.     /* actions          */      _XawTextActionsTable,
  3269.     /* num_actions      */      0,                /* Set in ClassInitialize. */
  3270.     /* resources        */      resources,
  3271.     /* num_ resource    */      XtNumber(resources),
  3272.     /* xrm_class        */      NULLQUARK,
  3273.     /* compress_motion  */      TRUE,
  3274.     /* compress_exposure*/      XtExposeGraphicsExpose | XtExposeNoExpose,
  3275.     /* compress_enterleave*/    TRUE,
  3276.     /* visible_interest */      FALSE,
  3277.     /* destroy          */      TextDestroy,
  3278.     /* resize           */      Resize,
  3279.     /* expose           */      ProcessExposeRegion,
  3280.     /* set_values       */      SetValues,
  3281.     /* set_values_hook  */    NULL,
  3282.     /* set_values_almost*/    XtInheritSetValuesAlmost,
  3283.     /* get_values_hook  */    GetValuesHook,
  3284.     /* accept_focus     */      NULL,
  3285.     /* version          */    XtVersion,
  3286.     /* callback_private */      NULL,
  3287.     /* tm_table         */      NULL,    /* set in ClassInitialize */
  3288.     /* query_geometry   */    XtInheritQueryGeometry,
  3289.     /* display_accelerator*/    XtInheritDisplayAccelerator,
  3290.     /* extension    */    NULL
  3291.   },
  3292.   { /* Simple fields */
  3293.     /* change_sensitive    */    ChangeSensitive
  3294.   },
  3295.   { /* text fields */
  3296.     /* empty            */    0
  3297.   }
  3298. };
  3299.  
  3300. WidgetClass textWidgetClass = (WidgetClass)&textClassRec;
  3301.