Home | History | Annotate | Line # | Download | only in src
      1 /***********************************************************
      2 
      3 Copyright 1987, 1988, 1994, 1998  The Open Group
      4 
      5 Permission to use, copy, modify, distribute, and sell this software and its
      6 documentation for any purpose is hereby granted without fee, provided that
      7 the above copyright notice appear in all copies and that both that
      8 copyright notice and this permission notice appear in supporting
      9 documentation.
     10 
     11 The above copyright notice and this permission notice shall be included in
     12 all copies or substantial portions of the Software.
     13 
     14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
     17 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
     18 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
     19 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     20 
     21 Except as contained in this notice, the name of The Open Group shall not be
     22 used in advertising or otherwise to promote the sale, use or other dealings
     23 in this Software without prior written authorization from The Open Group.
     24 
     25 
     26 Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
     27 
     28                         All Rights Reserved
     29 
     30 Permission to use, copy, modify, and distribute this software and its
     31 documentation for any purpose and without fee is hereby granted,
     32 provided that the above copyright notice appear in all copies and that
     33 both that copyright notice and this permission notice appear in
     34 supporting documentation, and that the name of Digital not be
     35 used in advertising or publicity pertaining to distribution of the
     36 software without specific, written prior permission.
     37 
     38 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
     39 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
     40 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
     41 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
     42 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
     43 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
     44 SOFTWARE.
     45 
     46 ******************************************************************/
     47 
     48 /*
     49  * Copyright (c) 1998 by The XFree86 Project, Inc.
     50  *
     51  * Permission is hereby granted, free of charge, to any person obtaining a
     52  * copy of this software and associated documentation files (the "Software"),
     53  * to deal in the Software without restriction, including without limitation
     54  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     55  * and/or sell copies of the Software, and to permit persons to whom the
     56  * Software is furnished to do so, subject to the following conditions:
     57  *
     58  * The above copyright notice and this permission notice shall be included in
     59  * all copies or substantial portions of the Software.
     60  *
     61  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     62  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     63  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     64  * THE XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
     65  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
     66  * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     67  * SOFTWARE.
     68  *
     69  * Except as contained in this notice, the name of the XFree86 Project shall
     70  * not be used in advertising or otherwise to promote the sale, use or other
     71  * dealings in this Software without prior written authorization from the
     72  * XFree86 Project.
     73  */
     74 
     75 #ifdef HAVE_CONFIG_H
     76 #include <config.h>
     77 #endif
     78 #include <stdio.h>
     79 #include <X11/IntrinsicP.h>
     80 #include <X11/StringDefs.h>
     81 #include <X11/Shell.h>
     82 #include <X11/Xatom.h>
     83 #include <X11/Xfuncs.h>
     84 #include <X11/Xutil.h>
     85 #include <X11/Xmu/Misc.h>
     86 #include <X11/Xmu/Xmu.h>
     87 #include <X11/Xaw/Cardinals.h>
     88 #include <X11/Xaw/MultiSinkP.h>
     89 #include <X11/Xaw/TextP.h>
     90 #include <X11/Xaw/TextSrcP.h>
     91 #include <X11/Xaw/TextSinkP.h>
     92 #include <X11/Xaw/Scrollbar.h>
     93 #include <X11/Xaw/XawImP.h>
     94 #include <X11/Xaw/XawInit.h>
     95 #include "Private.h"
     96 #include "XawI18n.h"
     97 
     98 #ifndef MAX_LEN_CT
     99 #define MAX_LEN_CT	6	/* for sequence: ESC $ ( A \xx \xx */
    100 #endif
    101 
    102 unsigned long FMT8BIT = 0L;
    103 unsigned long XawFmt8Bit = 0L;
    104 unsigned long XawFmtWide = 0L;
    105 
    106 #define SinkClearToBG		_XawTextSinkClearToBackground
    107 
    108 #define SrcScan			XawTextSourceScan
    109 #define SrcRead			XawTextSourceRead
    110 #define SrcReplace		XawTextSourceReplace
    111 #define SrcSearch		XawTextSourceSearch
    112 #define SrcCvtSel		XawTextSourceConvertSelection
    113 #define SrcSetSelection		XawTextSourceSetSelection
    114 
    115 #define MULTI_CLICK_TIME	500L
    116 
    117 #define SRC_CHANGE_NONE		0
    118 #define SRC_CHANGE_AFTER	1
    119 #define SRC_CHANGE_BEFORE	2
    120 #define SRC_CHANGE_OVERLAP	3
    121 
    122 #define Superclass (&simpleClassRec)
    123 
    124 /*
    125  * Compute a the maximum length of a cut buffer that we can pass at any
    126  * time.  The 64 allows for the overhead of the Change Property request.
    127  */
    128 #define MAX_CUT_LEN(dpy)  (XMaxRequestSize(dpy) - 64)
    129 
    130 #define	ClearWindow(ctx)						     \
    131      _XawTextNeedsUpdating((ctx),					     \
    132 			   (ctx)->text.lt.top,				     \
    133 			   (ctx)->text.lt.info[ctx->text.lt.lines].position)
    134 
    135 /*
    136  * Class Methods
    137  */
    138 static void XawTextClassInitialize(void);
    139 static void XawTextInitialize(Widget, Widget, ArgList, Cardinal*);
    140 static void XawTextRealize(Widget, XtValueMask*, XSetWindowAttributes*);
    141 static void XawTextDestroy(Widget);
    142 static void XawTextResize(Widget);
    143 static void XawTextExpose(Widget, XEvent*, Region);
    144 static Boolean XawTextSetValues(Widget, Widget, Widget, ArgList, Cardinal*);
    145 static void XawTextGetValuesHook(Widget, ArgList, Cardinal*);
    146 static Bool XawTextChangeSensitive(Widget);
    147 
    148 /*
    149  * Prototypes
    150  */
    151 static XawTextPosition _BuildLineTable(TextWidget, XawTextPosition, int);
    152 static void _CreateCutBuffers(Display*);
    153 static Boolean TextConvertSelection(Widget, Atom*, Atom*, Atom*, XtPointer*,
    154 				unsigned long*, int*);
    155 static int CountLines(TextWidget, XawTextPosition, XawTextPosition);
    156 static void CreateHScrollBar(TextWidget);
    157 static void CreateVScrollBar(TextWidget);
    158 static void CvtStringToScrollMode(XrmValuePtr, Cardinal*,
    159 				  XrmValuePtr, XrmValuePtr);
    160 static Boolean CvtScrollModeToString(Display*, XrmValue*, Cardinal*,
    161 				     XrmValue*, XrmValue*, XtPointer*);
    162 static void CvtStringToWrapMode(XrmValuePtr, Cardinal*,
    163 				XrmValuePtr, XrmValuePtr);
    164 static Boolean CvtWrapModeToString(Display*, XrmValue*, Cardinal*,
    165 				   XrmValue*, XrmValue*, XtPointer*);
    166 static Boolean CvtStringToJustifyMode(Display*, XrmValue*, Cardinal*,
    167 				      XrmValue*, XrmValue*, XtPointer*);
    168 static Boolean CvtJustifyModeToString(Display*, XrmValue*, Cardinal*,
    169 				      XrmValue*, XrmValue*, XtPointer*);
    170 static void DestroyHScrollBar(TextWidget);
    171 static void DestroyVScrollBar(TextWidget);
    172 #ifndef OLDXAW
    173 static void DisplayText(Widget, XawTextPosition, XawTextPosition);
    174 #endif
    175 static void OldDisplayText(Widget, XawTextPosition, XawTextPosition);
    176 static void DisplayTextWindow(Widget);
    177 static void DoCopyArea(TextWidget, int, int, unsigned int, unsigned int,
    178 		       int, int);
    179 static void DoSelection(TextWidget, XawTextPosition, Time, Bool);
    180 static void ExtendSelection(TextWidget, XawTextPosition, Bool);
    181 static XawTextPosition FindGoodPosition(TextWidget, XawTextPosition);
    182 static void FlushUpdate(TextWidget);
    183 static int GetCutBufferNumber(Atom);
    184 static int GetMaxTextWidth(TextWidget);
    185 static unsigned int GetWidestLine(TextWidget);
    186 static void HScroll(Widget, XtPointer, XtPointer);
    187 static void HJump(Widget, XtPointer, XtPointer);
    188 static void InsertCursor(Widget, XawTextInsertState);
    189 static Bool LineAndXYForPosition(TextWidget, XawTextPosition, int*,
    190 				 int*, int*);
    191 static int LineForPosition(TextWidget, XawTextPosition);
    192 static void TextLoseSelection(Widget, Atom*);
    193 static Bool MatchSelection(Atom, XawTextSelection*);
    194 static void ModifySelection(TextWidget, XawTextPosition, XawTextPosition);
    195 static XawTextPosition PositionForXY(TextWidget, int, int);
    196 static void PositionHScrollBar(TextWidget);
    197 static void PositionVScrollBar(TextWidget);
    198 #ifndef OLDXAW
    199 static int ResolveColumnNumber(TextWidget);
    200 static int ResolveLineNumber(TextWidget);
    201 #endif
    202 static void _SetSelection(TextWidget, XawTextPosition, XawTextPosition,
    203 			  Atom*, Cardinal);
    204 static void TextSinkResize(Widget);
    205 static void UpdateTextInRectangle(TextWidget, XRectangle*);
    206 static void UpdateTextInLine(TextWidget, int, int, int);
    207 static void VScroll(Widget, XtPointer, XtPointer);
    208 static void VJump(Widget, XtPointer, XtPointer);
    209 
    210 /*
    211  * External
    212  */
    213 void _XawTextAlterSelection(TextWidget,
    214 			    XawTextSelectionMode, XawTextSelectionAction,
    215 			    String*, Cardinal*);
    216 void _XawTextCheckResize(TextWidget);
    217 void _XawTextClearAndCenterDisplay(TextWidget);
    218 void _XawTextExecuteUpdate(TextWidget);
    219 char *_XawTextGetText(TextWidget, XawTextPosition, XawTextPosition);
    220 void _XawTextPrepareToUpdate(TextWidget);
    221 int _XawTextReplace(TextWidget, XawTextPosition, XawTextPosition,
    222 		    XawTextBlock*);
    223 Atom *_XawTextSelectionList(TextWidget, String*, Cardinal);
    224 void _XawTextSetScrollBars(TextWidget);
    225 void _XawTextSetSelection(TextWidget, XawTextPosition, XawTextPosition,
    226 			  String*, Cardinal);
    227 void _XawTextVScroll(TextWidget, int);
    228 void XawTextScroll(TextWidget, int, int);
    229 void _XawTextSetSource(Widget, Widget, XawTextPosition, XawTextPosition);
    230 #ifndef OLDXAW
    231 void _XawTextSetLineAndColumnNumber(TextWidget, Bool);
    232 #endif
    233 void _XawTextSourceChanged(Widget, XawTextPosition, XawTextPosition,
    234 			   XawTextBlock*, int);
    235 
    236 /* Not used by other modules, but were extern on previous versions
    237  * of the library
    238  */
    239 void _XawTextShowPosition(TextWidget);
    240 
    241 /*
    242  * From TextAction.c
    243  */
    244 extern void _XawTextZapSelection(TextWidget, XEvent*, Bool);
    245 
    246 /*
    247  * From TextSrc.c
    248  */
    249 void _XawSourceAddText(Widget, Widget);
    250 void _XawSourceRemoveText(Widget, Widget, Bool);
    251 Bool _XawTextSourceNewLineAtEOF(Widget);
    252 
    253 /*
    254  * From TextSink.c
    255  */
    256 void _XawTextSinkClearToBackground(Widget, int, int, unsigned, unsigned);
    257 void _XawTextSinkDisplayText(Widget, int, int, XawTextPosition, XawTextPosition,
    258 			     Bool);
    259 
    260 /****************************************************************
    261  *
    262  * Full class record constant
    263  *
    264  ****************************************************************/
    265 /*
    266  * From TextTr.c
    267  */
    268 static XawTextSelectType defaultSelectTypes[] = {
    269   XawselectPosition,  XawselectAlphaNumeric, XawselectWord, XawselectLine,
    270   XawselectParagraph, XawselectAll,	     XawselectNull,
    271 };
    272 
    273 static XPointer defaultSelectTypesPtr = (XPointer)defaultSelectTypes;
    274 static Dimension defWidth = 100;
    275 static Dimension defHeight = DEFAULT_TEXT_HEIGHT;
    276 
    277 #define offset(field) XtOffsetOf(TextRec, field)
    278 static XtResource resources[] = {
    279   {
    280     XtNwidth,
    281     XtCWidth,
    282     XtRDimension,
    283     sizeof(Dimension),
    284     offset(core.width),
    285     XtRDimension,
    286     (XtPointer)&defWidth
    287   },
    288   {
    289     XtNcursor,
    290     XtCCursor,
    291     XtRCursor,
    292     sizeof(Cursor),
    293     offset(simple.cursor),
    294     XtRString,
    295     (XtPointer)"xterm"
    296   },
    297   {
    298     XtNheight,
    299     XtCHeight,
    300     XtRDimension,
    301     sizeof(Dimension),
    302     offset(core.height),
    303     XtRDimension,
    304     (XtPointer)&defHeight
    305   },
    306   {
    307     XtNdisplayPosition,
    308     XtCTextPosition,
    309     XtRInt,
    310     sizeof(XawTextPosition),
    311     offset(text.lt.top),
    312     XtRImmediate,
    313     (XtPointer)0
    314   },
    315   {
    316     XtNinsertPosition,
    317     XtCTextPosition,
    318     XtRInt,
    319     sizeof(XawTextPosition),
    320     offset(text.insertPos),
    321     XtRImmediate,
    322     (XtPointer)0
    323   },
    324   {
    325     XtNleftMargin,
    326     XtCMargin,
    327     XtRPosition,
    328     sizeof(Position),
    329     offset(text.r_margin.left),
    330     XtRImmediate,
    331     (XtPointer)2
    332   },
    333   {
    334     XtNrightMargin,
    335     XtCMargin,
    336     XtRPosition,
    337     sizeof(Position),
    338     offset(text.r_margin.right),
    339     XtRImmediate,
    340     (XtPointer)4
    341   },
    342   {
    343     XtNtopMargin,
    344     XtCMargin,
    345     XtRPosition,
    346     sizeof(Position),
    347     offset(text.r_margin.top),
    348     XtRImmediate,
    349     (XtPointer)2
    350   },
    351   {
    352     XtNbottomMargin,
    353     XtCMargin,
    354     XtRPosition,
    355     sizeof(Position),
    356     offset(text.r_margin.bottom),
    357     XtRImmediate,
    358     (XtPointer)2
    359   },
    360   {
    361     XtNselectTypes,
    362     XtCSelectTypes,
    363     XtRPointer,
    364     sizeof(XawTextSelectType*),
    365     offset(text.sarray),
    366     XtRPointer,
    367     (XtPointer)&defaultSelectTypesPtr
    368   },
    369   {
    370     XtNtextSource,
    371     XtCTextSource,
    372     XtRWidget,
    373     sizeof(Widget),
    374     offset(text.source),
    375     XtRImmediate,
    376     NULL
    377   },
    378   {
    379     XtNtextSink,
    380     XtCTextSink,
    381     XtRWidget,
    382     sizeof(Widget),
    383     offset(text.sink),
    384     XtRImmediate,
    385     NULL
    386   },
    387   {
    388     XtNdisplayCaret,
    389     XtCOutput,
    390     XtRBoolean,
    391     sizeof(Boolean),
    392     offset(text.display_caret),
    393     XtRImmediate,
    394     (XtPointer)True
    395   },
    396   {
    397     XtNscrollVertical,
    398     XtCScroll,
    399     XtRScrollMode,
    400     sizeof(XawTextScrollMode),
    401     offset(text.scroll_vert),
    402     XtRImmediate,
    403     (XtPointer)False
    404   },
    405   {
    406     XtNscrollHorizontal,
    407     XtCScroll,
    408     XtRScrollMode,
    409     sizeof(XawTextScrollMode),
    410     offset(text.scroll_horiz),
    411     XtRImmediate,
    412     (XtPointer)False
    413   },
    414   {
    415     XtNwrap,
    416     XtCWrap,
    417     XtRWrapMode,
    418     sizeof(XawTextWrapMode),
    419     offset(text.wrap),
    420     XtRImmediate,
    421     (XtPointer)XawtextWrapNever
    422   },
    423   {
    424     XtNautoFill,
    425     XtCAutoFill,
    426     XtRBoolean,
    427     sizeof(Boolean),
    428     offset(text.auto_fill),
    429     XtRImmediate,
    430     (XtPointer)False
    431   },
    432 #ifndef OLDXAW
    433   {
    434     XtNpositionCallback,
    435     XtCCallback,
    436     XtRCallback,
    437     sizeof(XtPointer),
    438     offset(text.position_callbacks),
    439     XtRCallback,
    440     NULL
    441   },
    442   {
    443     XtNleftColumn,
    444     XtCColumn,
    445     XtRShort,
    446     sizeof(short),
    447     offset(text.left_column),
    448     XtRImmediate,
    449     (XtPointer)0
    450   },
    451   {
    452     XtNrightColumn,
    453     XtCColumn,
    454     XtRShort,
    455     sizeof(short),
    456     offset(text.right_column),
    457     XtRImmediate,
    458     (XtPointer)0
    459   },
    460   {
    461     XtNjustifyMode,
    462     XtCJustifyMode,
    463     XtRJustifyMode,
    464     sizeof(XawTextJustifyMode),
    465     offset(text.justify),
    466     XtRImmediate,
    467     (XtPointer)XawjustifyLeft
    468   },
    469 #endif /* OLDXAW */
    470 };
    471 #undef offset
    472 
    473 #define done(address, type) \
    474 	{ toVal->size = sizeof(type); toVal->addr = (XPointer)address; }
    475 
    476 static XrmQuark QWrapNever, QWrapLine, QWrapWord;
    477 static XrmQuark QScrollNever, QScrollWhenNeeded, QScrollAlways;
    478 static XrmQuark QJustifyLeft, QJustifyRight, QJustifyCenter, QJustifyFull;
    479 
    480 /*ARGSUSED*/
    481 static void
    482 CvtStringToScrollMode(XrmValuePtr args _X_UNUSED, Cardinal *num_args _X_UNUSED,
    483 		      XrmValuePtr fromVal, XrmValuePtr toVal)
    484 {
    485     static XawTextScrollMode scrollMode = XawtextScrollNever;
    486     XrmQuark q;
    487     char name[32];
    488 
    489     XmuNCopyISOLatin1Lowered(name, (char *)fromVal->addr, sizeof(name));
    490     q = XrmStringToQuark(name);
    491 
    492     if (q == QScrollNever || q == QScrollWhenNeeded)
    493 	scrollMode = XawtextScrollNever;
    494     else if (q == QScrollAlways)
    495 	scrollMode = XawtextScrollAlways;
    496     else if (strcmp(name, "true") == 0 || strcmp(name, "1") == 0)
    497 	scrollMode = XawtextScrollAlways;
    498     else if (strcmp(name, "false") == 0 || strcmp(name, "0") == 0)
    499 	scrollMode = XawtextScrollNever;
    500     else
    501 	XtStringConversionWarning((char *)fromVal->addr, XtRScrollMode);
    502 
    503     done(&scrollMode, XawTextScrollMode);
    504 }
    505 
    506 /*ARGSUSED*/
    507 static Boolean
    508 CvtScrollModeToString(Display *dpy, XrmValue *args _X_UNUSED, Cardinal *num_args _X_UNUSED,
    509 		      XrmValue *fromVal, XrmValue *toVal _X_UNUSED, XtPointer *data _X_UNUSED)
    510 {
    511     static String buffer;
    512     Cardinal size;
    513 
    514     switch (*(XawTextScrollMode *)fromVal->addr) {
    515 	case XawtextScrollNever:
    516 	case XawtextScrollWhenNeeded:
    517 	    buffer = XtEtextScrollNever;
    518 	    break;
    519 	case XawtextScrollAlways:
    520 	    buffer = XtEtextScrollAlways;
    521 	    break;
    522 	default:
    523 	    XawTypeToStringWarning(dpy, XtRScrollMode);
    524 	    toVal->addr = NULL;
    525 	    toVal->size = 0;
    526 	    return (False);
    527     }
    528     size = (Cardinal)strlen(buffer) + 1;
    529     if (toVal->addr != NULL) {
    530 	if (toVal->size < size)	{
    531 	    toVal->size = size;
    532 	    return (False);
    533 	}
    534 	strcpy((char *)toVal->addr, buffer);
    535     }
    536     else
    537 	toVal->addr = (XPointer)buffer;
    538     toVal->size = sizeof(String);
    539 
    540     return (True);
    541 }
    542 
    543 /*ARGSUSED*/
    544 static void
    545 CvtStringToWrapMode(XrmValuePtr args _X_UNUSED, Cardinal *num_args _X_UNUSED,
    546 		    XrmValuePtr fromVal, XrmValuePtr toVal)
    547 {
    548     static XawTextWrapMode wrapMode = XawtextWrapNever;
    549     XrmQuark q;
    550     char lowerName[6];
    551 
    552     XmuNCopyISOLatin1Lowered(lowerName, (char *)fromVal->addr,
    553 			     sizeof(lowerName));
    554     q = XrmStringToQuark(lowerName);
    555 
    556     if (q == QWrapNever)
    557 	wrapMode = XawtextWrapNever;
    558     else if (q == QWrapLine)
    559 	wrapMode = XawtextWrapLine;
    560     else if (q == QWrapWord)
    561 	wrapMode = XawtextWrapWord;
    562     else
    563 	XtStringConversionWarning((char *)fromVal->addr, XtRWrapMode);
    564 
    565     done(&wrapMode, XawTextWrapMode);
    566 }
    567 
    568 /*ARGSUSED*/
    569 static Boolean
    570 CvtWrapModeToString(Display *dpy, XrmValue *args _X_UNUSED, Cardinal *num_args _X_UNUSED,
    571 		    XrmValue *fromVal, XrmValue *toVal _X_UNUSED, XtPointer *data _X_UNUSED)
    572 {
    573     static String buffer;
    574     Cardinal size;
    575 
    576     switch (*(XawTextWrapMode *)fromVal->addr) {
    577 	case XawtextWrapNever:
    578 	    buffer = XtEtextWrapNever;
    579 	    break;
    580 	case XawtextWrapLine:
    581 	    buffer = XtEtextWrapLine;
    582 	    break;
    583 	case XawtextWrapWord:
    584 	    buffer = XtEtextWrapWord;
    585 	    break;
    586 	default:
    587 	    XawTypeToStringWarning(dpy, XtRWrapMode);
    588 	    toVal->addr = NULL;
    589 	    toVal->size = 0;
    590 	    return (False);
    591     }
    592     size = (Cardinal)strlen(buffer) + 1;
    593     if (toVal->addr != NULL) {
    594 	if (toVal->size < size)	{
    595 	    toVal->size = size;
    596 	    return (False);
    597 	}
    598 	strcpy((char *)toVal->addr, buffer);
    599     }
    600     else
    601 	toVal->addr = (XPointer)buffer;
    602     toVal->size = sizeof(String);
    603 
    604     return (True);
    605 }
    606 
    607 /*ARGSUSED*/
    608 static Boolean
    609 CvtStringToJustifyMode(Display *dpy _X_UNUSED, XrmValue *args _X_UNUSED, Cardinal *num_args _X_UNUSED,
    610 		       XrmValue *fromVal, XrmValue *toVal, XtPointer *data _X_UNUSED)
    611 {
    612     XawTextJustifyMode justify;
    613     XrmQuark q;
    614     char lowerName[8];
    615 
    616     XmuNCopyISOLatin1Lowered(lowerName, (char *)fromVal->addr,
    617 			   sizeof(lowerName));
    618     q = XrmStringToQuark(lowerName);
    619 
    620     if (q == QJustifyLeft)
    621 	justify = XawjustifyLeft;
    622     else if (q == QJustifyRight)
    623 	justify = XawjustifyRight;
    624     else if (q == QJustifyCenter)
    625 	justify = XawjustifyCenter;
    626     else if(q ==  QJustifyFull)
    627 	justify = XawjustifyFull;
    628     else {
    629 	XtStringConversionWarning((char *)fromVal->addr, XtRJustifyMode);
    630 	return (False);
    631     }
    632 
    633     toVal->size = sizeof(XawTextJustifyMode);
    634     *(XawTextJustifyMode *)(toVal->addr) = justify;
    635 
    636     return (True);
    637 }
    638 
    639 
    640 /*ARGSUSED*/
    641 static Boolean
    642 CvtJustifyModeToString(Display *dpy, XrmValue *args _X_UNUSED, Cardinal *num_args _X_UNUSED,
    643 		       XrmValue *fromVal, XrmValue *toVal, XtPointer *data _X_UNUSED)
    644 {
    645     static String buffer;
    646     Cardinal size;
    647 
    648     switch (*(XawTextJustifyMode *)fromVal->addr) {
    649 	case XawjustifyLeft:
    650 	    buffer = XtEtextJustifyLeft;
    651 	    break;
    652 	case XawjustifyRight:
    653 	    buffer = XtEtextJustifyRight;
    654 	    break;
    655 	case XawjustifyCenter:
    656 	    buffer = XtEtextJustifyCenter;
    657 	    break;
    658 	case XawjustifyFull:
    659 	    buffer = XtEtextJustifyFull;
    660 	    break;
    661 	default:
    662 	    XawTypeToStringWarning(dpy, XtRJustifyMode);
    663 	    toVal->addr = NULL;
    664 	    toVal->size = 0;
    665 	    return (False);
    666     }
    667     size = (Cardinal)strlen(buffer) + 1;
    668     if (toVal->addr != NULL) {
    669 	if (toVal->size < size)	{
    670 	    toVal->size = size;
    671 	    return (False);
    672 	}
    673 	strcpy((char *)toVal->addr, buffer);
    674     }
    675     else
    676 	toVal->addr = (XPointer)buffer;
    677     toVal->size = sizeof(String);
    678 
    679     return (True);
    680 }
    681 
    682 #undef done
    683 
    684 static void
    685 XawTextClassInitialize(void)
    686 {
    687     if (!XawFmt8Bit)
    688 	FMT8BIT = XawFmt8Bit = (unsigned long)XrmPermStringToQuark("FMT8BIT");
    689     if (!XawFmtWide)
    690 	XawFmtWide = (unsigned long)XrmPermStringToQuark("FMTWIDE");
    691 
    692     XawInitializeWidgetSet();
    693 
    694     textClassRec.core_class.num_actions = _XawTextActionsTableCount;
    695 
    696     QWrapNever	= XrmPermStringToQuark(XtEtextWrapNever);
    697     QWrapLine	= XrmPermStringToQuark(XtEtextWrapLine);
    698     QWrapWord	= XrmPermStringToQuark(XtEtextWrapWord);
    699     XtAddConverter(XtRString, XtRWrapMode, CvtStringToWrapMode, NULL, 0);
    700     XtSetTypeConverter(XtRWrapMode, XtRString, CvtWrapModeToString,
    701 		       NULL, 0, XtCacheNone, NULL);
    702     QScrollNever = XrmPermStringToQuark(XtEtextScrollNever);
    703     QScrollWhenNeeded = XrmPermStringToQuark(XtEtextScrollWhenNeeded);
    704     QScrollAlways = XrmPermStringToQuark(XtEtextScrollAlways);
    705     XtAddConverter(XtRString, XtRScrollMode, CvtStringToScrollMode,
    706 		   NULL, 0);
    707     XtSetTypeConverter(XtRScrollMode, XtRString, CvtScrollModeToString,
    708 		       NULL, 0, XtCacheNone, NULL);
    709     QJustifyLeft   = XrmPermStringToQuark(XtEtextJustifyLeft);
    710     QJustifyRight  = XrmPermStringToQuark(XtEtextJustifyRight);
    711     QJustifyCenter = XrmPermStringToQuark(XtEtextJustifyCenter);
    712     QJustifyFull   = XrmPermStringToQuark(XtEtextJustifyFull);
    713     XtSetTypeConverter(XtRString, XtRJustifyMode, CvtStringToJustifyMode,
    714 		       NULL, 0, XtCacheNone, NULL);
    715     XtSetTypeConverter(XtRJustifyMode, XtRString, CvtJustifyModeToString,
    716 		       NULL, 0, XtCacheNone, NULL);
    717 }
    718 
    719 /*
    720  * Function:
    721  *	PositionHScrollBar
    722  *
    723  * Parameters:
    724  *	ctx - text widget
    725  *
    726  * Description:
    727  *	Positions the Horizontal scrollbar.
    728  */
    729 static void
    730 PositionHScrollBar(TextWidget ctx)
    731 {
    732     Widget hbar = ctx->text.hbar, vbar = ctx->text.vbar;
    733     Position x, y;
    734     Dimension width, height;
    735 
    736     if (ctx->text.hbar == NULL)
    737 	return;
    738 
    739     if (vbar != NULL)
    740 	x = (Position)XtWidth(vbar);
    741     else
    742 	x = (Position)(-XtBorderWidth(hbar));
    743     y = (Position)(XtHeight(ctx) - XtHeight(hbar) - XtBorderWidth(hbar));
    744     if (vbar != NULL) {
    745 	width = (Dimension)(XtWidth(ctx) - XtWidth(vbar) - XtBorderWidth(vbar));
    746 	if (width > XtWidth(ctx))
    747 	    width = XtWidth(ctx);
    748     }
    749     else
    750 	width = XtWidth(ctx);
    751     height = XtHeight(hbar);
    752 
    753     XtConfigureWidget(hbar, x, y, width, height, XtBorderWidth(hbar));
    754 }
    755 
    756 /*
    757  * Function:
    758  *	PositionVScrollBar
    759  *
    760  * Parameters:
    761  *	ctx - text widget
    762  *
    763  * Description:
    764  *	Positions the Vertical scrollbar.
    765  */
    766 static void
    767 PositionVScrollBar(TextWidget ctx)
    768 {
    769     Widget vbar = ctx->text.vbar;
    770     Position x, y;
    771     Dimension width, height;
    772 
    773     if (vbar == NULL)
    774 	return;
    775 
    776     x = y = (Position)(-XtBorderWidth(vbar));
    777     height = XtHeight(ctx);
    778     width = XtWidth(vbar);
    779 
    780     XtConfigureWidget(vbar, x, y, width, height, XtBorderWidth(vbar));
    781 }
    782 
    783 static void
    784 CreateVScrollBar(TextWidget ctx)
    785 {
    786     Widget vbar;
    787 
    788     if (ctx->text.vbar != NULL)
    789 	return;
    790 
    791     ctx->text.vbar = vbar =
    792 	XtCreateWidget("vScrollbar", scrollbarWidgetClass, (Widget)ctx, NULL, 0);
    793     XtAddCallback(vbar, XtNscrollProc, VScroll, (XtPointer)ctx);
    794     XtAddCallback(vbar, XtNjumpProc, VJump, (XtPointer)ctx);
    795 
    796     ctx->text.r_margin.left += (Position) (XtWidth(vbar) + XtBorderWidth(vbar));
    797     ctx->text.left_margin = ctx->text.margin.left = ctx->text.r_margin.left;
    798 
    799     PositionVScrollBar(ctx);
    800     PositionHScrollBar(ctx);
    801     TextSinkResize(ctx->text.sink);
    802 
    803     if (XtIsRealized((Widget)ctx)) {
    804 	XtRealizeWidget(vbar);
    805 	XtMapWidget(vbar);
    806     }
    807     XtSetKeyboardFocus(vbar, (Widget)ctx);
    808 }
    809 
    810 /*
    811  * Function:
    812  *	DestroyVScrollBar
    813  *
    814  * Parameters:
    815  *	ctx - parent text widget
    816  *
    817  * Description:
    818  *	Removes vertical ScrollBar.
    819  */
    820 static void
    821 DestroyVScrollBar(TextWidget ctx)
    822 {
    823     Widget vbar = ctx->text.vbar;
    824 
    825     if (vbar == NULL)
    826 	return;
    827 
    828     ctx->text.r_margin.left = (Position)(ctx->text.r_margin.left - (XtWidth(vbar) + XtBorderWidth(vbar)));
    829     ctx->text.left_margin = ctx->text.margin.left = ctx->text.r_margin.left;
    830 
    831     XtDestroyWidget(vbar);
    832     ctx->text.vbar = NULL;
    833     if (!ctx->core.being_destroyed) {
    834 	PositionHScrollBar(ctx);
    835 	TextSinkResize(ctx->text.sink);
    836     }
    837 }
    838 
    839 static void
    840 CreateHScrollBar(TextWidget ctx)
    841 {
    842     Arg args[1];
    843     Widget hbar;
    844     int bottom;
    845 
    846     if (ctx->text.hbar != NULL)
    847 	return;
    848 
    849     XtSetArg(args[0], XtNorientation, XtorientHorizontal);
    850     ctx->text.hbar = hbar =
    851 	XtCreateWidget("hScrollbar", scrollbarWidgetClass, (Widget)ctx, args, 1);
    852     XtAddCallback(hbar, XtNscrollProc, HScroll, (XtPointer)ctx);
    853     XtAddCallback(hbar, XtNjumpProc, HJump, (XtPointer)ctx);
    854 
    855     bottom = ctx->text.r_margin.bottom + XtHeight(hbar) + XtBorderWidth(hbar);
    856 
    857     ctx->text.margin.bottom = ctx->text.r_margin.bottom = (Position)bottom;
    858 
    859     PositionHScrollBar(ctx);
    860     TextSinkResize(ctx->text.sink);
    861 
    862     if (XtIsRealized((Widget)ctx)) {
    863 	XtRealizeWidget(hbar);
    864 	XtMapWidget(hbar);
    865     }
    866     XtSetKeyboardFocus(hbar, (Widget)ctx);
    867 }
    868 
    869 /*
    870  * Function:
    871  *	DestroyHScrollBar
    872  *
    873  * Parameters:
    874  *	ctx - parent text widget
    875  *
    876  * Description:
    877  *	Removes horizontal ScrollBar.
    878  */
    879 static void
    880 DestroyHScrollBar(TextWidget ctx)
    881 {
    882     Widget hbar = ctx->text.hbar;
    883 
    884     if (hbar == NULL)
    885 	return;
    886 
    887     ctx->text.r_margin.bottom = (Position)(ctx->text.r_margin.bottom
    888 					   - (XtHeight(hbar)
    889 					    + XtBorderWidth(hbar)));
    890     ctx->text.margin.bottom = ctx->text.r_margin.bottom;
    891 
    892     XtDestroyWidget(hbar);
    893     ctx->text.hbar = NULL;
    894     if (!ctx->core.being_destroyed)
    895 	TextSinkResize(ctx->text.sink);
    896 }
    897 
    898 /*ARGSUSED*/
    899 static void
    900 XawTextInitialize(Widget request _X_UNUSED, Widget cnew,
    901 		  ArgList args _X_UNUSED, Cardinal *num_args _X_UNUSED)
    902 {
    903     TextWidget ctx = (TextWidget)cnew;
    904 
    905     ctx->text.lt.lines = 0;
    906     ctx->text.lt.info = (XawTextLineTableEntry *)
    907 	XtCalloc(1, sizeof(XawTextLineTableEntry));
    908 #ifndef OLDXAW
    909     ctx->text.lt.base_line = 1;
    910 #endif
    911     (void)bzero(&ctx->text.origSel, sizeof(XawTextSelection));
    912     (void)bzero(&ctx->text.s, sizeof(XawTextSelection));
    913     ctx->text.s.type = XawselectPosition;
    914     ctx->text.salt = NULL;
    915     ctx->text.hbar = ctx->text.vbar = NULL;
    916     ctx->text.lasttime = 0;
    917     ctx->text.time = 0;
    918     ctx->text.showposition = True;
    919     ctx->text.lastPos = ctx->text.source != NULL ?
    920 			XawTextGetLastPosition(ctx) : 0;
    921     ctx->text.file_insert = NULL;
    922     ctx->text.search = NULL;
    923     ctx->text.update = XmuNewScanline(0, 0, 0);
    924     ctx->text.gc = XtGetGC(cnew, 0, 0);
    925     ctx->text.hasfocus = False;
    926     ctx->text.margin = ctx->text.r_margin; /* Structure copy */
    927     ctx->text.left_margin = ctx->text.r_margin.left;
    928     ctx->text.update_disabled = False;
    929     ctx->text.clear_to_eol = True;
    930     ctx->text.old_insert = -1;
    931     ctx->text.mult = 1;
    932     ctx->text.salt2 = NULL;
    933     ctx->text.from_left = -1;
    934 
    935 #ifndef OLDXAW
    936     ctx->text.numeric = False;
    937     ctx->text.selection_state = False;
    938     ctx->text.kill_ring = 0;
    939 
    940     ctx->text.line_number = -1;
    941     ctx->text.column_number = -1;
    942     ctx->text.source_changed = SRC_CHANGE_NONE;
    943 
    944     ctx->text.kill_ring_ptr = NULL;
    945     ctx->text.overwrite = False;
    946 #endif
    947 
    948     if (XtHeight(ctx) == DEFAULT_TEXT_HEIGHT) {
    949 	XtHeight(ctx) = (Dimension)VMargins(ctx);
    950 	if (ctx->text.sink != NULL)
    951 	    XtHeight(ctx) += (Dimension) XawTextSinkMaxHeight(ctx->text.sink, 1);
    952     }
    953 
    954     if (ctx->text.scroll_vert == XawtextScrollAlways)
    955 	CreateVScrollBar(ctx);
    956     if (ctx->text.scroll_horiz == XawtextScrollAlways)
    957 	CreateHScrollBar(ctx);
    958 
    959 #ifndef OLDXAW
    960     if (ctx->text.left_column < 0)
    961 	ctx->text.left_column = 0;
    962     if (ctx->text.right_column < 0)
    963 	ctx->text.right_column = 0;
    964 #endif
    965 }
    966 
    967 static void
    968 XawTextRealize(Widget w, XtValueMask *mask, XSetWindowAttributes *attr)
    969 {
    970     TextWidget ctx = (TextWidget)w;
    971 
    972     (*textClassRec.core_class.superclass->core_class.realize)(w, mask, attr);
    973 
    974     if (ctx->text.hbar != NULL) {
    975 	XtRealizeWidget(ctx->text.hbar);
    976 	XtMapWidget(ctx->text.hbar);
    977     }
    978 
    979     if (ctx->text.vbar != NULL) {
    980 	XtRealizeWidget(ctx->text.vbar);
    981 	XtMapWidget(ctx->text.vbar);
    982     }
    983 
    984     _XawTextBuildLineTable(ctx, ctx->text.lt.top, True);
    985 
    986 #ifndef OLDXAW
    987     _XawTextSetLineAndColumnNumber(ctx, True);
    988 #endif
    989 }
    990 
    991 /* Utility routines for support of Text */
    992 static void
    993 _CreateCutBuffers(Display *d)
    994 {
    995     static struct _DisplayRec {
    996 	struct _DisplayRec *next;
    997 	Display *dpy;
    998     } *dpy_list = NULL;
    999     struct _DisplayRec *dpy_ptr;
   1000 
   1001     for (dpy_ptr = dpy_list; dpy_ptr != NULL; dpy_ptr = dpy_ptr->next)
   1002 	if (dpy_ptr->dpy == d)
   1003 	    return;
   1004 
   1005     dpy_ptr = XtNew(struct _DisplayRec);
   1006     dpy_ptr->next = dpy_list;
   1007     dpy_ptr->dpy = d;
   1008     dpy_list = dpy_ptr;
   1009 
   1010 #define Create(buffer) \
   1011   XChangeProperty(d, RootWindow(d, 0), buffer, XA_STRING, 8, \
   1012 		  PropModeAppend, NULL, 0);
   1013 
   1014     Create(XA_CUT_BUFFER0);
   1015     Create(XA_CUT_BUFFER1);
   1016     Create(XA_CUT_BUFFER2);
   1017     Create(XA_CUT_BUFFER3);
   1018     Create(XA_CUT_BUFFER4);
   1019     Create(XA_CUT_BUFFER5);
   1020     Create(XA_CUT_BUFFER6);
   1021     Create(XA_CUT_BUFFER7);
   1022 
   1023 #undef Create
   1024 }
   1025 
   1026 /*
   1027  * Procedure to manage insert cursor visibility for editable text.  It uses
   1028  * the value of ctx->insertPos and an implicit argument. In the event that
   1029  * position is immediately preceded by an eol graphic, then the insert cursor
   1030  * is displayed at the beginning of the next line.
   1031  */
   1032 static void
   1033 InsertCursor(Widget w, XawTextInsertState state)
   1034 {
   1035     TextWidget ctx = (TextWidget)w;
   1036     int x, y;
   1037     int line;
   1038 
   1039     if (ctx->text.lt.lines < 1)
   1040 	return;
   1041 
   1042     if (ctx->text.display_caret &&
   1043 	LineAndXYForPosition(ctx, ctx->text.insertPos, &line, &x, &y)) {
   1044 	if (line < ctx->text.lt.lines)
   1045 	    y += (ctx->text.lt.info[line + 1].y - ctx->text.lt.info[line].y) + 1;
   1046 	else
   1047 	    y += (ctx->text.lt.info[line].y - ctx->text.lt.info[line - 1].y) + 1;
   1048 
   1049 	XawTextSinkInsertCursor(ctx->text.sink, (Position)x, (Position)y, state);
   1050     }
   1051 
   1052     /* Keep Input Method up to speed  */
   1053     if (ctx->simple.international) {
   1054 	Arg list[1];
   1055 
   1056 	XtSetArg(list[0], XtNinsertPosition, ctx->text.insertPos);
   1057 	_XawImSetValues(w, list, 1);
   1058     }
   1059 }
   1060 
   1061 /*
   1062  * Procedure to register a span of text that is no longer valid on the display
   1063  * It is used to avoid a number of small, and potentially overlapping, screen
   1064  * updates.
   1065 */
   1066 void
   1067 _XawTextNeedsUpdating(TextWidget ctx,
   1068 		      XawTextPosition left, XawTextPosition right)
   1069 {
   1070     if (left >= right)
   1071 	return;
   1072     else  {
   1073 	XmuSegment segment = {
   1074 	    .x1 = (int)left,
   1075 	    .x2 = (int)right
   1076 	};
   1077 
   1078 	(void)XmuScanlineOrSegment(ctx->text.update, &segment);
   1079     }
   1080 }
   1081 
   1082 /*
   1083  * Procedure to read a span of text in Ascii form. This is purely a hack and
   1084  * we probably need to add a function to sources to provide this functionality.
   1085  * [note: this is really a private procedure but is used in multiple modules].
   1086  */
   1087 char *
   1088 _XawTextGetText(TextWidget ctx, XawTextPosition left, XawTextPosition right)
   1089 {
   1090     char *result, *tempResult;
   1091     XawTextBlock text;
   1092     int bytes;
   1093 
   1094     if (XawTextFormat(ctx, XawFmt8Bit))
   1095 	bytes = sizeof(unsigned char);
   1096     else if (XawTextFormat(ctx, XawFmtWide))
   1097 	bytes = sizeof(wchar_t);
   1098     else /* if there is another format, add here */
   1099 	bytes = 1;
   1100 
   1101     /* leave space for ZERO */
   1102     tempResult = result = XtMalloc((unsigned)(right - left + ONE) * (unsigned)bytes);
   1103 
   1104     while (left < right) {
   1105 	left = SrcRead(ctx->text.source, left, &text, (int)(right - left));
   1106 	if (!text.length)
   1107 	    break;
   1108 	memmove(tempResult, text.ptr, (unsigned)(text.length * bytes));
   1109 	tempResult += text.length * bytes;
   1110     }
   1111 
   1112     if (bytes == sizeof(wchar_t))
   1113 	*((wchar_t*)tempResult) = (wchar_t)0;
   1114     else
   1115 	*tempResult = '\0';
   1116 
   1117     return (result);
   1118 }
   1119 
   1120 /* Like _XawTextGetText, but enforces ICCCM STRING type encoding.  This
   1121  * routine is currently used to put just the ASCII chars in the selection
   1122  * into a cut buffer.
   1123  */
   1124 char *
   1125 _XawTextGetSTRING(TextWidget ctx, XawTextPosition left, XawTextPosition right)
   1126 {
   1127     /* allow ESC in accordance with ICCCM */
   1128     if (XawTextFormat(ctx, XawFmtWide)) {
   1129 	MultiSinkObject sink = (MultiSinkObject)ctx->text.sink;
   1130 	wchar_t *ws = (wchar_t *)_XawTextGetText(ctx, left, right);
   1131 	long n = (long)wcslen(ws);
   1132 	long i, j;
   1133 
   1134 	for (j = 0, i = 0; j < n; j++) {
   1135 	    wchar_t wc = ws[j];
   1136 	    if (XwcTextEscapement (sink->multi_sink.fontset, &wc, 1)
   1137 		|| (wc == _Xaw_atowc(XawTAB)) || (wc == _Xaw_atowc(XawLF))
   1138 		|| (wc == _Xaw_atowc(XawESC)))
   1139 		ws[i++] = wc;
   1140 	}
   1141 	ws[i] = (wchar_t)0;
   1142 	return ((char *)ws);
   1143     }
   1144     else {
   1145 	unsigned char *s = (unsigned char *)_XawTextGetText(ctx, left, right);
   1146 	/* only HT and NL control chars are allowed, strip out others */
   1147 	long n = (long)strlen((char *)s);
   1148 	long i = 0, j;
   1149 
   1150 	for (j = 0; j < n; j++)	{
   1151 	    unsigned char c = s[j];
   1152 	    if (((c >= 0x20) && c <= 0x7f)
   1153 		||(c >= 0xa0) || (c == XawTAB) || (c == XawLF)
   1154 		|| (c == XawESC)) {
   1155 		s[i] = c;
   1156 		i++;
   1157 	    }
   1158 	}
   1159 	s[i] = 0;
   1160 
   1161 	return ((char *)s);
   1162     }
   1163 }
   1164 
   1165 /*
   1166  * This routine maps an x and y position in a window that is displaying text
   1167  * into the corresponding position in the source.
   1168  */
   1169 static XawTextPosition
   1170 PositionForXY(TextWidget ctx, int x, int y)
   1171 {
   1172     int fromx, line, width, height;
   1173     XawTextPosition position;
   1174 
   1175     if (ctx->text.lt.lines == 0)
   1176 	return (0);
   1177 
   1178     for (line = 0; line < ctx->text.lt.lines - 1; line++) {
   1179 	if (y <= ctx->text.lt.info[line + 1].y)
   1180 	    break;
   1181     }
   1182     position = ctx->text.lt.info[line].position;
   1183     if (position >= ctx->text.lastPos)
   1184 	return (ctx->text.lastPos);
   1185     fromx = ctx->text.left_margin;
   1186     XawTextSinkFindPosition(ctx->text.sink, position, fromx, x - fromx,
   1187 			    False, &position, &width, &height);
   1188 
   1189     if (position > ctx->text.lastPos)
   1190 	return (ctx->text.lastPos);
   1191 
   1192     if (position >= ctx->text.lt.info[line + 1].position)
   1193 	position = SrcScan(ctx->text.source, ctx->text.lt.info[line + 1].position,
   1194 			   XawstPositions, XawsdLeft, 1, True);
   1195 
   1196     return (position);
   1197 }
   1198 
   1199 /*
   1200  * This routine maps a source position in to the corresponding line number
   1201  * of the text that is displayed in the window.
   1202  */
   1203 static int
   1204 LineForPosition(TextWidget ctx, XawTextPosition position)
   1205 {
   1206     int line;
   1207 
   1208     for (line = 0; line < ctx->text.lt.lines; line++)
   1209 	if (position < ctx->text.lt.info[line + 1].position)
   1210 	    break;
   1211 
   1212     return (line);
   1213 }
   1214 
   1215 /*
   1216  * This routine maps a source position into the corresponding line number
   1217  * and the x, y coordinates of the text that is displayed in the window.
   1218  */
   1219 static Bool
   1220 LineAndXYForPosition(TextWidget ctx, XawTextPosition pos,
   1221 		     int *line, int *x, int *y)
   1222 {
   1223     Boolean visible;
   1224 
   1225     *line = 0;
   1226     *x = ctx->text.left_margin;
   1227     *y = ctx->text.margin.top + 1;
   1228     if ((visible = IsPositionVisible(ctx, pos)) != False) {
   1229 	XawTextPosition linePos, endPos;
   1230 	int realW, realH;
   1231 
   1232 	*line = LineForPosition(ctx, pos);
   1233 	*y = ctx->text.lt.info[*line].y;
   1234 	linePos = ctx->text.lt.info[*line].position;
   1235 	XawTextSinkFindDistance(ctx->text.sink, linePos,
   1236 				*x, pos, &realW, &endPos, &realH);
   1237 	*x += realW;
   1238     }
   1239 
   1240     return (visible);
   1241 }
   1242 
   1243 /*
   1244  * This routine builds a line table. It does this by starting at the
   1245  * specified position and measuring text to determine the staring position
   1246  * of each line to be displayed. It also determines and saves in the
   1247  * linetable all the required metrics for displaying a given line (e.g.
   1248  * x offset, y offset, line length, etc.).
   1249  */
   1250 void
   1251 _XawTextBuildLineTable(TextWidget ctx, XawTextPosition position,
   1252 		       _XtBoolean force_rebuild)
   1253 {
   1254     int lines = 0;
   1255     Cardinal size;
   1256 
   1257     if ((int)XtHeight(ctx) > VMargins(ctx)) {
   1258 	Dimension height = (Dimension)(XtHeight(ctx) - VMargins(ctx));
   1259 	lines = XawTextSinkMaxLines(ctx->text.sink, height);
   1260     }
   1261     size = (Cardinal)(sizeof(XawTextLineTableEntry) * (size_t)(lines + 1));
   1262 
   1263     if (lines != ctx->text.lt.lines || ctx->text.lt.info == NULL) {
   1264 	ctx->text.lt.info = (XawTextLineTableEntry *)
   1265 	    XtRealloc((char *)ctx->text.lt.info, size);
   1266 	ctx->text.lt.lines = lines;
   1267 	force_rebuild = True;
   1268     }
   1269 
   1270     if (force_rebuild) {
   1271 	(void)bzero((char *)ctx->text.lt.info, size);
   1272 	/* force a text update in the first text line if it is visible */
   1273 	ctx->text.lt.info[0].position = (XawTextPosition)-1;
   1274     }
   1275     if (position != ctx->text.lt.info[0].position) {
   1276 	(void)_BuildLineTable(ctx, position, 0);
   1277 	ctx->text.clear_to_eol = True;
   1278     }
   1279 }
   1280 
   1281 /*
   1282  * We may need to resize the line table here, since there maybe lines with
   1283  * different fonts (that can be shorter or taller than the default one)
   1284  */
   1285 static XawTextPosition
   1286 _BuildLineTable(TextWidget ctx, XawTextPosition position, int line)
   1287 {
   1288     XawTextLineTableEntry *lt = ctx->text.lt.info + line;
   1289     XawTextPosition end, update_from = -1;
   1290     Position y;
   1291     int wwidth, width, height;
   1292 #ifndef OLDXAW
   1293     Widget src = ctx->text.source;
   1294 #endif
   1295     int max_y = (int)XtHeight(ctx) - (int)ctx->text.margin.bottom;
   1296 
   1297     if (ctx->text.wrap == XawtextWrapNever)
   1298 	wwidth = 0x7fffffff;
   1299     else
   1300 	wwidth = GetMaxTextWidth(ctx);
   1301 
   1302     /* XXX y may change, due to font size changes. See later */
   1303     y = line == 0 ? ctx->text.margin.top : lt->y;
   1304 
   1305 #ifndef OLDXAW
   1306     if (ctx->text.lt.base_line < 0) {
   1307 	if (line == 0)
   1308 	    ctx->text.lt.top = position;
   1309     }
   1310     else if (line == 0) {
   1311 	XawTextPosition pos = ctx->text.lt.top;
   1312 	int base_line = ctx->text.lt.base_line;
   1313 
   1314 	if (position == 0)
   1315 	    base_line = 1;
   1316 	else if (ctx->text.lt.base_line == 0 ||
   1317 		 ctx->text.source_changed == SRC_CHANGE_OVERLAP) {
   1318 	    pos = 0;
   1319 	    base_line = 1;
   1320 
   1321 	    while (pos < position) {
   1322 		pos = SrcScan(src, pos, XawstEOL, XawsdRight, 1, True);
   1323 		if (pos <= position) {
   1324 		    ++base_line;
   1325 		    if (pos == ctx->text.lastPos) {
   1326 			base_line -= !_XawTextSourceNewLineAtEOF(src);
   1327 			break;
   1328 		    }
   1329 		}
   1330 	    }
   1331 	}
   1332 	else if (ctx->text.wrap == XawtextWrapNever
   1333 		 && IsPositionVisible(ctx, position))
   1334 	    base_line += LineForPosition(ctx, position);
   1335 	else if (pos < position) {
   1336 	    while (pos < position) {
   1337 		pos = SrcScan(src, pos, XawstEOL, XawsdRight, 1, True);
   1338 		if (pos <= position) {
   1339 		    ++base_line;
   1340 		    if (pos == ctx->text.lastPos) {
   1341 			base_line -= !_XawTextSourceNewLineAtEOF(src);
   1342 			break;
   1343 		    }
   1344 		}
   1345 	    }
   1346 	}
   1347 	else if (pos > position) {
   1348 	    while (pos > position) {
   1349 		pos = SrcScan(src, pos, XawstEOL, XawsdLeft, 1, False);
   1350 		if (--pos >= position)
   1351 		    --base_line;
   1352 	    }
   1353 	}
   1354 
   1355 	ctx->text.lt.top = position;
   1356 	ctx->text.lt.base_line = base_line;
   1357     }
   1358 #else
   1359     if (line == 0)
   1360 	ctx->text.lt.top = position;
   1361 #endif
   1362 
   1363     /* CONSTCOND */
   1364     while (True) {
   1365 	XawTextSinkFindPosition(ctx->text.sink, position, ctx->text.left_margin,
   1366 				wwidth, ctx->text.wrap == XawtextWrapWord,
   1367 				&end, &width, &height);
   1368 
   1369 	if (lt->position != position) {
   1370 	    _XawTextNeedsUpdating(ctx, position,
   1371 				  end <= position ? position + 1 : end);
   1372 	    ctx->text.clear_to_eol = True;
   1373 	    lt->position = position;
   1374 	}
   1375 	if (lt->y != y) {
   1376 	    if (update_from < 0)
   1377 		update_from = line == 0 ?
   1378 		    ctx->text.lt.info[0].position :
   1379 		    ctx->text.lt.info[line - 1].position;
   1380 	    lt->y = y;
   1381 	    ctx->text.clear_to_eol = True;
   1382 	}
   1383 	if (lt->textWidth != (Cardinal)width) {
   1384 	    if (lt->textWidth > (Cardinal)width)
   1385 		ctx->text.clear_to_eol = True;
   1386 	    lt->textWidth = (Dimension)width;
   1387 	}
   1388 	y = (Position)(y + height);
   1389 
   1390 	if (end > ctx->text.lastPos) {
   1391 	    position = end;
   1392 	    ctx->text.clear_to_eol = True;
   1393 	    _XawTextNeedsUpdating(ctx, end, end + ctx->text.lt.lines - line);
   1394 	    while (line++ < ctx->text.lt.lines) {
   1395 		if (line > 1 && y > max_y) {
   1396 		    ctx->text.lt.lines = line - 1;
   1397 		    break;
   1398 		}
   1399 		++lt;
   1400 		if (lt->y != y) {
   1401 		    if (update_from < 0)
   1402 			update_from = line < 2 ?
   1403 			    ctx->text.lt.info[0].position :
   1404 			    ctx->text.lt.info[line - 2].position;
   1405 		    lt->y = y;
   1406 		}
   1407 		lt->position = ++position;
   1408 		lt->textWidth = 0;
   1409 		y = (Position)(y + height);
   1410 	    }
   1411 	    if (update_from >= 0)
   1412 		_XawTextNeedsUpdating(ctx, update_from,
   1413 				      ctx->text.lt.info[ctx->text.lt.lines].position);
   1414 	    _XawTextSetScrollBars(ctx);
   1415 
   1416 	    return (ctx->text.lastPos);
   1417 	}
   1418 
   1419 	if (line && y > max_y)
   1420 	    /* will return in the next loop */
   1421 	    ctx->text.lt.lines = line;
   1422 
   1423 	if (++line > ctx->text.lt.lines && y < max_y) {
   1424 	/* grow the line table */
   1425 	    ctx->text.lt.info = (XawTextLineTableEntry *)
   1426 		XtRealloc((char *)ctx->text.lt.info,
   1427 			  (Cardinal)(sizeof(XawTextLineTableEntry) * (size_t)(line + 1)));
   1428 	    lt = ctx->text.lt.info + line;
   1429 	    bzero(lt, sizeof(XawTextLineTableEntry));
   1430 	    ++ctx->text.lt.lines;
   1431 	}
   1432 	else
   1433 	    ++lt;
   1434 	if (position == end)
   1435 	    ++position;
   1436 	else
   1437 	    position = end;
   1438 
   1439 	if (line > ctx->text.lt.lines) {
   1440 	    if (update_from >= 0)
   1441 		_XawTextNeedsUpdating(ctx, update_from,
   1442 				      ctx->text.lt.info[ctx->text.lt.lines].position);
   1443 	    _XawTextSetScrollBars(ctx);
   1444 
   1445 	    return (position);
   1446 	}
   1447     }
   1448     /*NOTREACHED*/
   1449 }
   1450 
   1451 /*
   1452  * Function:
   1453  *	GetWidestLine
   1454  *
   1455  * Parameters:
   1456  *	ctx - text widget
   1457  *
   1458  * Description:
   1459  *	  Returns the width (in pixels) of the widest line that
   1460  *		     is currently visible.
   1461  *
   1462  * Returns:
   1463  *	The width of the widest line
   1464  */
   1465 static unsigned int
   1466 GetWidestLine(TextWidget ctx)
   1467 {
   1468     int i;
   1469     unsigned int widest;
   1470     XawTextLineTablePtr lt = &(ctx->text.lt);
   1471 
   1472     for (i = 0, widest = 0; i < lt->lines; i++)
   1473 	if (widest < lt->info[i].textWidth)
   1474 	    widest = lt->info[i].textWidth;
   1475 
   1476     return (widest);
   1477 }
   1478 
   1479 /*
   1480  * This routine is used by Text to notify an associated scrollbar of the
   1481  * correct metrics (position and shown fraction) for the text being currently
   1482  * displayed in the window.
   1483  */
   1484 void
   1485 _XawTextSetScrollBars(TextWidget ctx)
   1486 {
   1487     float first;
   1488 
   1489     if (ctx->text.scroll_vert == XawtextScrollAlways) {
   1490 	float last;
   1491 
   1492 	if (ctx->text.lastPos == 0)
   1493 	    first = 0.0;
   1494 	else
   1495 	    first = (float)ctx->text.lt.top / (float)ctx->text.lastPos;
   1496 
   1497 	if (ctx->text.lt.info[ctx->text.lt.lines].position < ctx->text.lastPos)
   1498 	    last = (float)ctx->text.lt.info[ctx->text.lt.lines].position /
   1499 		   (float)ctx->text.lastPos;
   1500 	else
   1501 	    last = 1.0;
   1502 
   1503 	XawScrollbarSetThumb(ctx->text.vbar, first, last - first);
   1504     }
   1505 
   1506     if (ctx->text.scroll_horiz == XawtextScrollAlways) {
   1507 	unsigned value = GetWidestLine(ctx);
   1508 	float denom = (float)value;
   1509 	float widest;
   1510 
   1511 	if (denom <= 0)
   1512 	    denom = (float)((int)XtWidth(ctx) - RHMargins(ctx));
   1513 	if (denom <= 0)
   1514 	    denom = 1;
   1515 	widest = (float)((int)XtWidth(ctx) - RHMargins(ctx)) / denom;
   1516 	first = (float)(ctx->text.r_margin.left - ctx->text.left_margin);
   1517 	first /= denom;
   1518 
   1519 	XawScrollbarSetThumb(ctx->text.hbar, first, widest);
   1520     }
   1521 }
   1522 
   1523 static void
   1524 DoCopyArea(TextWidget ctx, int src_x, int src_y,
   1525 	   unsigned int width, unsigned int height, int dst_x, int dst_y)
   1526 {
   1527     int x1, y1, x2, y2;
   1528 
   1529     x1 = ctx->text.r_margin.left;
   1530     y1 = ctx->text.r_margin.top;
   1531     x2 = XtWidth(ctx) - ctx->text.r_margin.right;
   1532     y2 = XtHeight(ctx) - ctx->text.r_margin.bottom;
   1533 
   1534     if (x1 >= x2 || y1 >= y2)
   1535 	return;
   1536 
   1537     src_x = XawMax(x1, XawMin(src_x, x2));
   1538     src_y = XawMax(y1, XawMin(src_y, y2));
   1539     dst_x = XawMax(x1, XawMin(dst_x, x2));
   1540     dst_y = XawMax(y1, XawMin(dst_y, y2));
   1541     width = (unsigned)XawMax(0, XawMin(x2 - dst_x, (int)width));
   1542     height = (unsigned)XawMax(0, XawMin(y2 - dst_y, (int)height));
   1543 
   1544     XCopyArea(XtDisplay(ctx), XtWindow(ctx), XtWindow(ctx), ctx->text.gc,
   1545 	      src_x, src_y, width, height, dst_x, dst_y);
   1546 }
   1547 
   1548 /*
   1549  * Function:
   1550  *	XawTextScroll
   1551  *
   1552  * Parameters:
   1553  *	ctx	- text widget
   1554  *	vlines	- number of lines to scroll vertically
   1555  *	hpixels	- number of pixels to scroll horizontally
   1556  *
   1557  * Description:
   1558  *	Generic function for scrolling the text window.
   1559  *	Allows vertical and horizontal scroll at the same time.
   1560  */
   1561 void
   1562 XawTextScroll(TextWidget ctx, int vlines, int hpixels)
   1563 {
   1564     XawTextPosition top, tmp, update_from, update_to;
   1565     XawTextLineTable *lt;
   1566     Arg arglist[1];
   1567     int y0, y1, y2, count, dim, wwidth, lines = ctx->text.lt.lines;
   1568     int vwidth, vheight;	/* visible width and height */
   1569     Bool scroll;
   1570 
   1571     vwidth = (int)XtWidth(ctx) - RHMargins(ctx);
   1572     vheight = (int)XtHeight(ctx) - RVMargins(ctx);
   1573     lt = &ctx->text.lt;
   1574 
   1575     if (!lt || vwidth <= 0 || vheight <= 0)
   1576 	return;
   1577 
   1578     if ((scroll = ctx->core.background_pixmap == XtUnspecifiedPixmap) == True) {
   1579 	dim = lt->info[1].y - lt->info[0].y;
   1580 	for (count = 1; count < lt->lines - 1; count++)
   1581 	    if (lt->info[count + 1].y - lt->info[count].y != dim) {
   1582 		scroll = False;
   1583 		break;
   1584 	    }
   1585     }
   1586 
   1587     wwidth = GetMaxTextWidth(ctx);
   1588 
   1589     /*
   1590      * Do the horizontall scrolling
   1591      */
   1592     if (hpixels < 0 && ctx->text.left_margin - hpixels > ctx->text.r_margin.left)
   1593 	hpixels = ctx->text.left_margin - ctx->text.r_margin.left;
   1594     ctx->text.left_margin -= hpixels;
   1595 
   1596     update_from = lt->top;	/* remember the old value */
   1597     /*
   1598      *	 Checks the requested number of lines and calculates the top
   1599      * of the line table
   1600      */
   1601     if (vlines < 0) {		  /* VScroll Up */
   1602 	if (IsPositionVisible(ctx, 0))
   1603 	    vlines = 0;
   1604 	else if (ctx->text.wrap != XawtextWrapNever) {
   1605 	    XawTextPosition end;
   1606 	    int n_lines = 0;
   1607 
   1608 	    count = -vlines;
   1609 	    end = lt->top;
   1610 	    while (n_lines < count) {
   1611 		top = SrcScan(ctx->text.source, end, XawstEOL,
   1612 			      XawsdLeft, 2, False);
   1613 		n_lines += CountLines(ctx, top, end);
   1614 		end = top;
   1615 	    }
   1616 
   1617 	    while (count++ < n_lines) {
   1618 		tmp = top;
   1619 		XawTextSinkFindPosition(ctx->text.sink, top,
   1620 					ctx->text.left_margin,
   1621 					wwidth,ctx->text.wrap == XawtextWrapWord,
   1622 					&top, &dim, &dim);
   1623 		if (tmp == top)
   1624 		    ++top;
   1625 	    }
   1626 	}
   1627 	else
   1628 	    top = SrcScan(ctx->text.source, lt->top, XawstEOL,
   1629 			  XawsdLeft, -vlines + 1, False);
   1630 	if (-vlines >= ctx->text.lt.lines)
   1631 	  scroll = False;
   1632      }
   1633     else if (vlines > 0) {	  /* VScroll Down */
   1634 	if (LineForPosition(ctx, ctx->text.lastPos) == 0)
   1635 	    vlines = 0;
   1636 	if (vlines < lt->lines)
   1637 	    top = XawMin(lt->info[vlines].position, ctx->text.lastPos);
   1638 	else if (ctx->text.wrap == XawtextWrapNever)
   1639 	    top = SrcScan(ctx->text.source,
   1640 			  SrcScan(ctx->text.source, lt->top,
   1641 				  XawstEOL, XawsdRight, vlines,
   1642 				  True),
   1643 			  XawstEOL, XawsdLeft, 1, False);
   1644 	else {
   1645 	    top = lt->top;
   1646 	    count = 0;
   1647 	    while (count++ < vlines) {
   1648 		tmp = top;
   1649 		XawTextSinkFindPosition(ctx->text.sink, top,
   1650 					ctx->text.left_margin,
   1651 					wwidth, ctx->text.wrap == XawtextWrapWord,
   1652 					&top, &dim, &dim);
   1653 		if (tmp == top)
   1654 		    ++top;
   1655 	    }
   1656 	}
   1657 	if (vlines >= ctx->text.lt.lines
   1658 	    || lt->info[vlines].position >= ctx->text.lastPos)
   1659 	    scroll = False;
   1660     }
   1661 
   1662     if (!vlines) {
   1663 	if (hpixels) {
   1664 	    ClearWindow(ctx);
   1665 	    ctx->text.clear_to_eol = True;
   1666 	}
   1667 	_XawTextSetScrollBars(ctx);
   1668 	return;
   1669     }
   1670 
   1671     /* Flushes any pending updates. Normally, there may be a call to
   1672      * XawTextUnsetSelection not yet updated.
   1673      */
   1674     if (!hpixels && scroll) {
   1675 	ctx->text.clear_to_eol = True;
   1676 	FlushUpdate(ctx);
   1677     }
   1678 
   1679     /*
   1680      * Rebuild the line table, doing the vertical scroll
   1681      */
   1682     (void)_BuildLineTable(ctx, top, 0);
   1683     lt = &ctx->text.lt;
   1684     if (scroll) {
   1685 	for (count = 0; count < lt->lines - 1; count++)
   1686 	    if (lt->info[count + 1].y - lt->info[count].y != dim) {
   1687 		scroll = False;
   1688 		break;
   1689 	    }
   1690     }
   1691 
   1692     XtSetArg(arglist[0], XtNinsertPosition, lt->top + lt->lines);
   1693     _XawImSetValues((Widget)ctx, arglist, 1);
   1694 
   1695     if (hpixels || !scroll || lines != lt->lines)
   1696 	return;
   1697 
   1698     /* _BuildLineTable updates everything if the top position changes.
   1699      * It is not required here.
   1700      */
   1701     (void)XmuScanlineXor(ctx->text.update, ctx->text.update);
   1702     if (vlines < 0 && IsPositionVisible(ctx, 0))
   1703 	vlines = -LineForPosition(ctx, update_from);
   1704 
   1705     y0 = ctx->text.r_margin.top;
   1706     if (vlines < 0) {
   1707 	update_from = lt->top;
   1708 	update_to = lt->info[-vlines + 1].position - 1;
   1709 	y1 = lt->info[lt->lines + vlines].y;
   1710 	y2 = lt->info[-vlines].y;
   1711 	DoCopyArea(ctx, ctx->text.r_margin.left, y0, (unsigned)vwidth,
   1712 		   (unsigned)(y1 - y0),
   1713 		   ctx->text.r_margin.left, y2);
   1714     }
   1715     else {
   1716 	update_from = lt->info[lt->lines - vlines].position;
   1717 	update_to = lt->info[lt->lines].position;
   1718 	y2 = lt->info[vlines].y;
   1719 	DoCopyArea(ctx, ctx->text.r_margin.left, y2,
   1720 		   (unsigned)vwidth, (unsigned)(lt->info[lt->lines].y - y2),
   1721 		   ctx->text.r_margin.left, y0);
   1722     }
   1723     _XawTextNeedsUpdating(ctx, update_from, update_to);
   1724     ctx->text.clear_to_eol = True;
   1725 }
   1726 
   1727 /*
   1728  * The routine will scroll the displayed text by lines.  If the arg  is
   1729  * positive, move up; otherwise, move down. [note: this is really a private
   1730  * procedure but is used in multiple modules].
   1731  */
   1732 void
   1733 _XawTextVScroll(TextWidget ctx, int n)
   1734 {
   1735   XawTextScroll(ctx, n, 0);
   1736 }
   1737 
   1738 /*ARGSUSED*/
   1739 static void
   1740 HScroll(Widget w _X_UNUSED, XtPointer closure, XtPointer callData)
   1741 {
   1742     TextWidget ctx = (TextWidget)closure;
   1743     long pixels = (long)callData;
   1744 
   1745     if (pixels > 0) {
   1746 	long max;
   1747 
   1748 	max = (int)GetWidestLine(ctx) + ctx->text.left_margin -
   1749 	      ctx->text.r_margin.left;
   1750 	max = XawMax(0, max);
   1751 	pixels = XawMin(pixels, max);
   1752     }
   1753 
   1754     if (pixels) {
   1755 	_XawTextPrepareToUpdate(ctx);
   1756 	XawTextScroll(ctx, 0, (int)pixels);
   1757 	_XawTextExecuteUpdate(ctx);
   1758     }
   1759 }
   1760 
   1761 /*ARGSUSED*/
   1762 static void
   1763 HJump(Widget w, XtPointer closure, XtPointer callData)
   1764 {
   1765     TextWidget ctx = (TextWidget)closure;
   1766     float percent = *(float *)callData;
   1767     unsigned value = GetWidestLine(ctx);
   1768     long pixels;
   1769 
   1770     pixels = ctx->text.left_margin -
   1771 	     (ctx->text.r_margin.left - (int)(percent * (float)value));
   1772 
   1773     HScroll(w, (XtPointer)ctx, (XtPointer)pixels);
   1774 }
   1775 
   1776 /*
   1777  * Function:
   1778  *	UpdateTextInLine
   1779  *
   1780  * Parameters:
   1781  *	ctx  - text widget
   1782  *	line - line to update
   1783  *	x1   - left pixel
   1784  *	x2   - right pixel
   1785  *
   1786  * Description:
   1787  *	Updates the text in the given line and pixel interval
   1788  */
   1789 static void
   1790 UpdateTextInLine(TextWidget ctx, int line, int x1, int x2)
   1791 {
   1792     XawTextLineTableEntry *lt = ctx->text.lt.info + line;
   1793     XawTextPosition left, right;
   1794     int from_x, width, height;
   1795 
   1796     if (lt->position >= ctx->text.lastPos
   1797 	|| ctx->text.left_margin > x2
   1798 	|| (int)lt->textWidth + ctx->text.left_margin < x1) {
   1799 	/* Mark line to be cleared */
   1800 	if (ctx->text.clear_to_eol)
   1801 	    _XawTextNeedsUpdating(ctx, lt->position, lt->position + 1);
   1802 	return;
   1803     }
   1804 
   1805     from_x = ctx->text.left_margin;
   1806     XawTextSinkFindPosition(ctx->text.sink, lt->position,
   1807 			    from_x, x1 - from_x,
   1808 			    False, &left, &width, &height);
   1809     if (line == ctx->text.lt.lines)
   1810 	right = -1;
   1811     else if ((Cardinal)x2 >= (lt->textWidth - (unsigned)from_x))
   1812 	right = lt[1].position - 1;
   1813     else {
   1814 	from_x += width;
   1815 	XawTextSinkFindPosition(ctx->text.sink, left,
   1816 				from_x, x2 - from_x,
   1817 				False, &right, &width, &height);
   1818     }
   1819 
   1820     if ((right < 0) || (right + 1 <= lt[1].position))
   1821 	++right;
   1822 
   1823     /* Mark text interval to be repainted */
   1824     _XawTextNeedsUpdating(ctx, left, right);
   1825 }
   1826 
   1827 /*
   1828  * The routine will scroll the displayed text by pixels.  If the calldata is
   1829  * positive, move up; otherwise, move down.
   1830  */
   1831 /*ARGSUSED*/
   1832 static void
   1833 VScroll(Widget w _X_UNUSED, XtPointer closure, XtPointer callData)
   1834 {
   1835     TextWidget ctx = (TextWidget)closure;
   1836     long height, lines = (long)callData;
   1837 
   1838     height = XtHeight(ctx) - VMargins(ctx);
   1839     if (height < 1)
   1840 	height = 1;
   1841     lines = (lines * ctx->text.lt.lines) / height;
   1842     _XawTextPrepareToUpdate(ctx);
   1843     XawTextScroll(ctx, (int)lines, 0);
   1844     _XawTextExecuteUpdate(ctx);
   1845 }
   1846 
   1847 /*ARGSUSED*/
   1848 static void
   1849 VJump(Widget w _X_UNUSED, XtPointer closure, XtPointer callData)
   1850 {
   1851     float percent = *(float *)callData;
   1852     TextWidget ctx = (TextWidget)closure;
   1853     XawTextPosition top, last, position, tmp;
   1854     XawTextLineTable *lt = &(ctx->text.lt);
   1855     int dim, vlines = 0, wwidth = GetMaxTextWidth(ctx);
   1856     Bool scroll = True;
   1857 
   1858     position = (XawTextPosition)(percent * (float)ctx->text.lastPos);
   1859     top = lt->top;
   1860 
   1861     if (!lt->lines || (position >= lt->top && position < lt->info[1].position)) {
   1862 	_XawTextSetScrollBars(ctx);
   1863 	return;
   1864     }
   1865 
   1866 #ifndef OLDXAW
   1867     ctx->text.lt.base_line = -1;
   1868 #endif
   1869 
   1870     if (position > lt->top) {	  /* VScroll Up */
   1871 	if (position > lt->top && position < lt->info[lt->lines].position)
   1872 	    vlines = LineForPosition(ctx, position);
   1873 	else {
   1874 	    scroll = False;
   1875 	    top = SrcScan(ctx->text.source, position, XawstEOL,
   1876 			  XawsdLeft, 1, False);
   1877 	    if (ctx->text.wrap != XawtextWrapNever) {
   1878 		last = top;
   1879 		while (last < position) {
   1880 		    tmp = last;
   1881 		    XawTextSinkFindPosition(ctx->text.sink, last,
   1882 					    ctx->text.left_margin, wwidth,
   1883 					    ctx->text.wrap == XawtextWrapWord,
   1884 					    &last, &dim, &dim);
   1885 		    if (last == tmp)
   1886 			++last;
   1887 		    if (last < position)
   1888 			top = last;
   1889 		}
   1890 	    }
   1891 	}
   1892     }
   1893     else {		  /* VScroll Down */
   1894 	/*
   1895 	 * Calculates the number of lines
   1896 	 */
   1897 	while (top > position) {
   1898 	    last = top;
   1899 	    top = SrcScan(ctx->text.source, top, XawstEOL,
   1900 			  XawsdLeft, 2, False);
   1901 	    vlines -= CountLines(ctx, top, last);
   1902 	    if (-vlines >= ctx->text.lt.lines) {
   1903 		scroll = False;
   1904 		top = SrcScan(ctx->text.source, position, XawstEOL,
   1905 			      XawsdLeft, 1, False);
   1906 		break;
   1907 	      }
   1908 	  }
   1909 	/*
   1910 	 * Normalize
   1911 	 */
   1912 	if (ctx->text.wrap != XawtextWrapNever) {
   1913 	    last = top;
   1914 	    while (last < position) {
   1915 		tmp = last;
   1916 		XawTextSinkFindPosition(ctx->text.sink, last,
   1917 					ctx->text.left_margin,
   1918 					wwidth,
   1919 					ctx->text.wrap == XawtextWrapWord,
   1920 					&last, &dim, &dim);
   1921 		if (last == tmp)
   1922 		    ++last;
   1923 		if (last < position)
   1924 		    top = last;
   1925 		++vlines;
   1926 	    }
   1927 	}
   1928     }
   1929 
   1930     if (vlines || !scroll) {
   1931 	_XawTextPrepareToUpdate(ctx);
   1932 	if (scroll)
   1933 	    XawTextScroll(ctx, vlines, 0);
   1934 	else
   1935 	    _BuildLineTable(ctx, top, 0);
   1936 	_XawTextExecuteUpdate(ctx);
   1937     }
   1938 }
   1939 
   1940 static Bool
   1941 MatchSelection(Atom selection, XawTextSelection *s)
   1942 {
   1943     Atom *match;
   1944     int count;
   1945 
   1946     for (count = 0, match = s->selections; count < s->atom_count;
   1947        match++, count++)
   1948     if (*match == selection)
   1949 	return (True);
   1950 
   1951   return (False);
   1952 }
   1953 
   1954 static Boolean
   1955 TextConvertSelection(Widget w, Atom *selection, Atom *target, Atom *type,
   1956 		 XtPointer *value, unsigned long *length, int *format)
   1957 {
   1958     Display *d = XtDisplay(w);
   1959     TextWidget ctx = (TextWidget)w;
   1960     Widget src = ctx->text.source;
   1961     XawTextEditType edit_mode;
   1962     XawTextSelectionSalt *salt = NULL;
   1963     XawTextSelection *s;
   1964 
   1965     if (*target == XA_TARGETS(d)) {
   1966 	Atom *targetP, *std_targets;
   1967 	unsigned long std_length;
   1968 
   1969 	if (SrcCvtSel(src, selection, target, type, value, length, format))
   1970 	    return (True);
   1971 	else {
   1972 	    Arg args[1];
   1973 
   1974 	    XtSetArg(args[0], XtNeditType, &edit_mode);
   1975 	    XtGetValues(src, args, ONE);
   1976 	}
   1977 
   1978 	XmuConvertStandardSelection(w, ctx->text.time, selection,
   1979 				    target, type, (XPointer*)&std_targets,
   1980 				    &std_length, format);
   1981 
   1982 	*length = 7 + (unsigned long)(edit_mode == XawtextEdit) + std_length;
   1983 	*value = XtMalloc((Cardinal)(sizeof(Atom)*(*length)));
   1984 	targetP = *(Atom**)value;
   1985 	*targetP++ = XA_STRING;
   1986 	*targetP++ = XA_TEXT(d);
   1987 	*targetP++ = XA_UTF8_STRING(d);
   1988 	*targetP++ = XA_COMPOUND_TEXT(d);
   1989 	*targetP++ = XA_LENGTH(d);
   1990 	*targetP++ = XA_LIST_LENGTH(d);
   1991 	*targetP++ = XA_CHARACTER_POSITION(d);
   1992 	if (edit_mode == XawtextEdit) {
   1993 	    *targetP++ = XA_DELETE(d);
   1994 	}
   1995 	(void)memmove((char*)targetP, (char*)std_targets,
   1996 		      sizeof(Atom) * std_length);
   1997 	XtFree((char*)std_targets);
   1998 	*type = XA_ATOM;
   1999 	*format = 32;
   2000 	return (True);
   2001     }
   2002 
   2003     if (SrcCvtSel(src, selection, target, type, value, length, format))
   2004 	return (True);
   2005 
   2006     if (MatchSelection(*selection, &ctx->text.s))
   2007 	s = &ctx->text.s;
   2008     else {
   2009 	for (salt = ctx->text.salt; salt; salt = salt->next)
   2010 	    if (MatchSelection(*selection, &salt->s))
   2011 		break;
   2012 	if (!salt)
   2013 	    return (False);
   2014 	s = &salt->s;
   2015     }
   2016     if (*target == XA_STRING
   2017 	|| *target == XA_TEXT(d)
   2018 	|| *target == XA_UTF8_STRING(d)
   2019 	|| *target == XA_COMPOUND_TEXT(d)) {
   2020 	if (*target == XA_TEXT(d)) {
   2021 	    if (XawTextFormat(ctx, XawFmtWide))
   2022 		*type = XA_COMPOUND_TEXT(d);
   2023 	    else
   2024 		*type = XA_STRING;
   2025 	}
   2026 	else
   2027 	    *type = *target;
   2028 	/*
   2029 	 * If salt is True, the salt->contents stores CT string,
   2030 	 * its length is measured in bytes.
   2031 	 * Refer to _XawTextSaltAwaySelection().
   2032 	 *
   2033 	 * by Li Yuhong, Mar. 20, 1991.
   2034 	 */
   2035 	if (!salt) {
   2036 	    *value = _XawTextGetSTRING(ctx, s->left, s->right);
   2037 	    if (XawTextFormat(ctx, XawFmtWide)) {
   2038 		XTextProperty textprop;
   2039 		if (XwcTextListToTextProperty(d, (wchar_t **)value, 1,
   2040 					      XCompoundTextStyle, &textprop)
   2041 		    <  Success) {
   2042 		    XtFree((char *)*value);
   2043 		    return (False);
   2044 		}
   2045 		XtFree((char *)*value);
   2046 		*value = (XtPointer)textprop.value;
   2047 		*length = textprop.nitems;
   2048 	    }
   2049 	    else
   2050 	        *length = strlen((char *)*value);
   2051 	}
   2052 	else {
   2053 	    *value = XtMalloc((Cardinal)((size_t)(salt->length + 1) * sizeof(unsigned char)));
   2054 	    strcpy ((char *)*value, salt->contents);
   2055 	    *length = (unsigned long)salt->length;
   2056 	}
   2057 	/* Got *value,*length, now in COMPOUND_TEXT format. */
   2058 	if (XawTextFormat(ctx, XawFmtWide) && *type == XA_STRING) {
   2059 	    wchar_t **wlist;
   2060 	    int count;
   2061 	    XTextProperty textprop = {
   2062 		.encoding = XA_COMPOUND_TEXT(d),
   2063 		.value = (unsigned char *)*value,
   2064 		.nitems = strlen(*value),
   2065 		.format = 8
   2066 	    };
   2067 
   2068 	    if (XwcTextPropertyToTextList(d, &textprop, &wlist, &count)
   2069 		 < Success
   2070 		|| count < 1) {
   2071 		XtFree((char *)*value);
   2072 		return (False);
   2073 	    }
   2074 	    XtFree((char *)*value);
   2075 	    if (XwcTextListToTextProperty(d, wlist, 1, XStringStyle, &textprop)
   2076 		 < Success) {
   2077 		XwcFreeStringList((wchar_t**) wlist);
   2078 		return (False);
   2079 	    }
   2080 	    *value = (XtPointer)textprop.value;
   2081 	    *length = textprop.nitems;
   2082 	    XwcFreeStringList(wlist);
   2083 	} else if (*type == XA_UTF8_STRING(d)) {
   2084 	    char **list;
   2085 	    int count;
   2086 	    XTextProperty textprop = {
   2087 		.encoding = XA_COMPOUND_TEXT(d),
   2088 		.value = (unsigned char *)*value,
   2089 		.nitems = strlen(*value),
   2090 		.format = 8
   2091 	    };
   2092 
   2093 	    if (Xutf8TextPropertyToTextList(d, &textprop, &list, &count)
   2094 		 < Success
   2095 		|| count < 1) {
   2096 		XtFree((char *)*value);
   2097 		return (False);
   2098 	    }
   2099 	    XtFree((char *)*value);
   2100 	    *value = *list;
   2101 	    *length = strlen(*list);
   2102 	    XFree(list);
   2103 	}
   2104 	*format = 8;
   2105 	return (True);
   2106     }
   2107 
   2108     if ((*target == XA_LIST_LENGTH(d)) || (*target == XA_LENGTH(d))) {
   2109 	long * temp;
   2110 
   2111 	temp = (long *)XtMalloc((unsigned)sizeof(long));
   2112 	if (*target == XA_LIST_LENGTH(d))
   2113 	    *temp = 1L;
   2114 	else			/* *target == XA_LENGTH(d) */
   2115 	    *temp = (long) (s->right - s->left);
   2116 
   2117 	*value = (XPointer)temp;
   2118 	*type = XA_INTEGER;
   2119 	*length = 1L;
   2120 	*format = 32;
   2121 	return (True);
   2122     }
   2123 
   2124     if (*target == XA_CHARACTER_POSITION(d)) {
   2125 	long * temp;
   2126 
   2127 	temp = (long *)XtMalloc((unsigned)(2 * sizeof(long)));
   2128 	temp[0] = (long)(s->left + 1);
   2129 	temp[1] = s->right;
   2130 	*value = (XPointer)temp;
   2131 	*type = XA_SPAN(d);
   2132 	*length = 2L;
   2133 	*format = 32;
   2134 	return (True);
   2135     }
   2136 
   2137     if (*target == XA_DELETE(d)) {
   2138 	if (!salt)
   2139 	    _XawTextZapSelection(ctx, NULL, True);
   2140 	*value = NULL;
   2141 	*type = XA_NULL(d);
   2142 	*length = 0;
   2143 	*format = 32;
   2144 	return (True);
   2145     }
   2146 
   2147     if (XmuConvertStandardSelection(w, ctx->text.time, selection, target, type,
   2148 				    (XPointer *)value, length, format))
   2149 	return (True);
   2150 
   2151     /* else */
   2152     return (False);
   2153 }
   2154 
   2155 /*
   2156  * Function:
   2157  *	GetCutBuffferNumber
   2158  *
   2159  * Parameters:
   2160  *	atom - atom to check
   2161  *
   2162  * Description:
   2163  *	Returns the number of the cut buffer.
   2164  *
   2165  * Returns:
   2166  *	The number of the cut buffer representing this atom or NOT_A_CUT_BUFFER
   2167  */
   2168 #define NOT_A_CUT_BUFFER -1
   2169 static int
   2170 GetCutBufferNumber(Atom atom)
   2171 {
   2172     if (atom == XA_CUT_BUFFER0) return (0);
   2173     if (atom == XA_CUT_BUFFER1) return (1);
   2174     if (atom == XA_CUT_BUFFER2) return (2);
   2175     if (atom == XA_CUT_BUFFER3) return (3);
   2176     if (atom == XA_CUT_BUFFER4) return (4);
   2177     if (atom == XA_CUT_BUFFER5) return (5);
   2178     if (atom == XA_CUT_BUFFER6) return (6);
   2179     if (atom == XA_CUT_BUFFER7) return (7);
   2180     return (NOT_A_CUT_BUFFER);
   2181 }
   2182 
   2183 static void
   2184 TextLoseSelection(Widget w, Atom *selection)
   2185 {
   2186     TextWidget ctx = (TextWidget)w;
   2187     Atom *atomP;
   2188     int i;
   2189     XawTextSelectionSalt*salt, *prevSalt, *nextSalt;
   2190 
   2191     atomP = ctx->text.s.selections;
   2192     for (i = 0 ; i < ctx->text.s.atom_count; i++, atomP++)
   2193 	if ((*selection == *atomP)
   2194 	    || (GetCutBufferNumber(*atomP) != NOT_A_CUT_BUFFER))
   2195 	    *atomP = (Atom)0;
   2196 
   2197     while (ctx->text.s.atom_count
   2198 	   && ctx->text.s.selections[ctx->text.s.atom_count - 1] == 0)
   2199 	ctx->text.s.atom_count--;
   2200 
   2201     /*
   2202      * Must walk the selection list in opposite order from UnsetSelection
   2203      */
   2204     atomP = ctx->text.s.selections;
   2205     for (i = 0 ; i < ctx->text.s.atom_count; i++, atomP++)
   2206 	if (*atomP == (Atom)0) {
   2207 	    *atomP = ctx->text.s.selections[--ctx->text.s.atom_count];
   2208 	    while (ctx->text.s.atom_count
   2209 		   && ctx->text.s.selections[ctx->text.s.atom_count-1] == 0)
   2210 		ctx->text.s.atom_count--;
   2211 	}
   2212 
   2213     if (ctx->text.s.atom_count == 0)
   2214 	ModifySelection(ctx, ctx->text.insertPos, ctx->text.insertPos);
   2215 
   2216     prevSalt = 0;
   2217     for (salt = ctx->text.salt; salt; salt = nextSalt) {
   2218 	atomP = salt->s.selections;
   2219 	nextSalt = salt->next;
   2220 	for (i = 0 ; i < salt->s.atom_count; i++, atomP++)
   2221 	    if (*selection == *atomP)
   2222 		*atomP = (Atom)0;
   2223 
   2224 	while (salt->s.atom_count
   2225 	       && salt->s.selections[salt->s.atom_count-1] == 0)
   2226 	    salt->s.atom_count--;
   2227 
   2228 	/*
   2229 	 * Must walk the selection list in opposite order from UnsetSelection
   2230 	 */
   2231 	atomP = salt->s.selections;
   2232 	for (i = 0 ; i < salt->s.atom_count; i++, atomP++)
   2233 	    if (*atomP == (Atom)0) {
   2234 		*atomP = salt->s.selections[--salt->s.atom_count];
   2235 		while (salt->s.atom_count
   2236 		       && salt->s.selections[salt->s.atom_count-1] == 0)
   2237 		    salt->s.atom_count--;
   2238 	    }
   2239 
   2240 	if (salt->s.atom_count == 0) {
   2241 	    XtFree ((char *) salt->s.selections);
   2242 	    XtFree (salt->contents);
   2243 	    if (prevSalt)
   2244 		prevSalt->next = nextSalt;
   2245 	    else
   2246 		ctx->text.salt = nextSalt;
   2247 	    XtFree((char *)salt);
   2248 	}
   2249 	else
   2250 	    prevSalt = salt;
   2251     }
   2252 }
   2253 
   2254 void
   2255 _XawTextSaltAwaySelection(TextWidget ctx, Atom *selections, int num_atoms)
   2256 {
   2257     XawTextSelectionSalt *salt;
   2258     int i, j;
   2259 
   2260     for (i = 0; i < num_atoms; i++)
   2261 	TextLoseSelection((Widget)ctx, selections + i);
   2262     if (num_atoms == 0)
   2263 	return;
   2264     salt = (XawTextSelectionSalt *)
   2265 	XtMalloc((unsigned)sizeof(XawTextSelectionSalt));
   2266     if (!salt)
   2267 	return;
   2268     salt->s.selections = (Atom *)XtMalloc((Cardinal)((size_t)num_atoms * sizeof(Atom)));
   2269     if (!salt->s.selections) {
   2270 	XtFree((char *)salt);
   2271 	return;
   2272     }
   2273     salt->s.left = ctx->text.s.left;
   2274     salt->s.right = ctx->text.s.right;
   2275     salt->s.type = ctx->text.s.type;
   2276     salt->contents = _XawTextGetSTRING(ctx, ctx->text.s.left, ctx->text.s.right);
   2277     if (XawTextFormat(ctx, XawFmtWide)) {
   2278 	XTextProperty textprop;
   2279 	if (XwcTextListToTextProperty(XtDisplay((Widget)ctx),
   2280 				      (wchar_t**)(&(salt->contents)), 1,
   2281 				      XCompoundTextStyle,
   2282 				      &textprop) < Success) {
   2283 	    XtFree(salt->contents);
   2284 	    salt->length = 0;
   2285 	    return;
   2286 	}
   2287 	XtFree(salt->contents);
   2288 	salt->contents = (char *)textprop.value;
   2289 	salt->length = (int)textprop.nitems;
   2290     }
   2291     else
   2292 	salt->length = (int)strlen (salt->contents);
   2293     salt->next = ctx->text.salt;
   2294     ctx->text.salt = salt;
   2295     j = 0;
   2296     for (i = 0; i < num_atoms; i++) {
   2297 	if (GetCutBufferNumber (selections[i]) == NOT_A_CUT_BUFFER) {
   2298 	    salt->s.selections[j++] = selections[i];
   2299 	    XtOwnSelection((Widget)ctx, selections[i], ctx->text.time,
   2300 			   TextConvertSelection, TextLoseSelection, NULL);
   2301 	}
   2302     }
   2303     salt->s.atom_count = j;
   2304 }
   2305 
   2306 static void
   2307 _SetSelection(TextWidget ctx, XawTextPosition left, XawTextPosition right,
   2308 	      Atom *selections, Cardinal count)
   2309 {
   2310 #ifndef OLDXAW
   2311     Cardinal i;
   2312     XawTextPosition pos;
   2313     TextSrcObject src = (TextSrcObject)ctx->text.source;
   2314 
   2315     for (i = 0; i < src->textSrc.num_text; i++) {
   2316 	TextWidget tw = (TextWidget)src->textSrc.text[i];
   2317 	Bool needs_updating = tw->text.old_insert < 0;
   2318 	Bool showposition = tw->text.showposition;
   2319 
   2320 	if (needs_updating) {
   2321 	    tw->text.showposition = False;
   2322 	    _XawTextPrepareToUpdate(tw);
   2323 	}
   2324 #else
   2325 	TextWidget tw = ctx;
   2326 	XawTextPosition pos;
   2327 #endif /* OLDXAW */
   2328 
   2329 	if (left < tw->text.s.left) {
   2330 	    pos = Min(right, tw->text.s.left);
   2331 	    _XawTextNeedsUpdating(tw, left, pos);
   2332 	}
   2333 	if (left > tw->text.s.left) {
   2334 	    pos = Min(left, tw->text.s.right);
   2335 	    _XawTextNeedsUpdating(tw, tw->text.s.left, pos);
   2336 	}
   2337 	if (right < tw->text.s.right) {
   2338 	    pos = Max(right, tw->text.s.left);
   2339 	    _XawTextNeedsUpdating(tw, pos, tw->text.s.right);
   2340 	}
   2341 	if (right > tw->text.s.right) {
   2342 	    pos = Max(left, tw->text.s.right);
   2343 	    _XawTextNeedsUpdating(tw, pos, right);
   2344 	}
   2345 
   2346 	tw->text.s.left = left;
   2347 	tw->text.s.right = right;
   2348 
   2349 #ifndef OLDXAW
   2350 	if (needs_updating) {
   2351 	    _XawTextExecuteUpdate(tw);
   2352 	    tw->text.showposition = (Boolean)showposition;
   2353 	}
   2354     }
   2355 #endif /* OLDXAW */
   2356 
   2357     SrcSetSelection(ctx->text.source, left, right,
   2358 		    (count == 0) ? None : selections[0]);
   2359 
   2360     if (left < right) {
   2361 	Widget w = (Widget)ctx;
   2362 
   2363 	while (count) {
   2364 	    Atom selection = selections[--count];
   2365 	    int buffer;
   2366 
   2367 	    /*
   2368 	     * If this is a cut buffer
   2369 	     */
   2370 	    if ((buffer = GetCutBufferNumber(selection)) != NOT_A_CUT_BUFFER) {
   2371 		unsigned char *ptr, *tptr;
   2372 		unsigned int amount, max_len = (unsigned)MAX_CUT_LEN(XtDisplay(w));
   2373 		unsigned long len;
   2374 
   2375 		tptr= ptr= (unsigned char *)_XawTextGetSTRING(ctx,
   2376 							      ctx->text.s.left,
   2377 							      ctx->text.s.right);
   2378 		if (XawTextFormat(ctx, XawFmtWide)) {
   2379 		    /*
   2380 		     * Only XA_STRING(Latin 1) is allowed in CUT_BUFFER,
   2381 		     * so we get it from wchar string, then free the wchar string
   2382 		     */
   2383 		    XTextProperty textprop;
   2384 
   2385 		    if (XwcTextListToTextProperty(XtDisplay(w), (wchar_t**)&ptr,
   2386 						  1, XStringStyle, &textprop)
   2387 			<  Success){
   2388 			XtFree((char *)ptr);
   2389 			return;
   2390 		    }
   2391 		    XtFree((char *)ptr);
   2392 		    tptr = ptr = textprop.value;
   2393 		}
   2394 		if (buffer == 0) {
   2395 		    _CreateCutBuffers(XtDisplay(w));
   2396 		    XRotateBuffers(XtDisplay(w), 1);
   2397 		}
   2398 		amount = (unsigned)Min ((len = strlen((char *)ptr)), max_len);
   2399 		XChangeProperty(XtDisplay(w), RootWindow(XtDisplay(w), 0),
   2400 				selection, XA_STRING, 8, PropModeReplace,
   2401 				ptr, (int)amount);
   2402 
   2403 		while (len > max_len) {
   2404 		    len -= max_len;
   2405 		    tptr += max_len;
   2406 		    amount = (unsigned) Min (len, max_len);
   2407 		    XChangeProperty(XtDisplay(w), RootWindow(XtDisplay(w), 0),
   2408 				    selection, XA_STRING, 8, PropModeAppend,
   2409 				    tptr, (int)amount);
   2410 		}
   2411 		XtFree ((char *)ptr);
   2412 	    }
   2413 	    else		/* This is a real selection */
   2414 		XtOwnSelection(w, selection, ctx->text.time, TextConvertSelection,
   2415 			       TextLoseSelection, NULL);
   2416 	}
   2417     }
   2418     else
   2419 	XawTextUnsetSelection((Widget)ctx);
   2420 }
   2421 
   2422 #ifndef OLDXAW
   2423 void
   2424 _XawTextSetLineAndColumnNumber(TextWidget ctx, Bool force)
   2425 {
   2426     int line_number, column_number;
   2427 
   2428     if (ctx->text.old_insert != ctx->text.insertPos &&
   2429 	ctx->text.lt.base_line < 0) {
   2430 	ctx->text.lt.base_line = 0;
   2431 	(void)_BuildLineTable(ctx, ctx->text.lt.top, 0);
   2432     }
   2433 
   2434     line_number = ResolveLineNumber(ctx);
   2435     column_number = ResolveColumnNumber(ctx);
   2436 
   2437     if (force || (ctx->text.column_number != column_number
   2438 		  || ctx->text.line_number != line_number)) {
   2439 	XawTextPositionInfo info;
   2440 
   2441 	ctx->text.line_number = info.line_number = line_number;
   2442 	ctx->text.column_number = (short)(info.column_number = column_number);
   2443 	info.insert_position = ctx->text.insertPos;
   2444 	info.last_position = ctx->text.lastPos;
   2445 	info.overwrite_mode = ctx->text.overwrite;
   2446 
   2447 	XtCallCallbacks((Widget)ctx, XtNpositionCallback, (XtPointer)&info);
   2448     }
   2449 }
   2450 
   2451 static int
   2452 ResolveColumnNumber(TextWidget ctx)
   2453 {
   2454     Widget src = ctx->text.source;
   2455     short column_number = 0;
   2456     XawTextPosition position;
   2457     XawTextBlock block;
   2458     unsigned long format = (unsigned long)_XawTextFormat(ctx);
   2459     TextSinkObject sink = (TextSinkObject)ctx->text.sink;
   2460     short *char_tabs = sink->text_sink.char_tabs;
   2461     int tab_count = sink->text_sink.tab_count;
   2462     int tab_index = 0, tab_column = 0, tab_base = 0;
   2463 
   2464     if (ctx->text.lt.base_line < 1)
   2465 	return (ctx->text.column_number);
   2466 
   2467     position = SrcScan(src, ctx->text.insertPos, XawstEOL, XawsdLeft, 1, False);
   2468     XawTextSourceRead(src, position, &block, (int)(ctx->text.insertPos - position));
   2469 
   2470     for (; position < ctx->text.insertPos; position++) {
   2471 	if (position - block.firstPos >= block.length)
   2472 	    XawTextSourceRead(src, position, &block, (int)(ctx->text.insertPos - position));
   2473 	if ((format == XawFmt8Bit && block.ptr[position - block.firstPos] == '\t') ||
   2474 	    (format == XawFmtWide && ((wchar_t*)block.ptr)[position - block.firstPos] == _Xaw_atowc(XawTAB))) {
   2475 	    while (tab_base + tab_column <= column_number) {
   2476 		if (tab_count) {
   2477 		    for (; tab_index < tab_count; ++tab_index)
   2478 			if (tab_base + char_tabs[tab_index] > column_number) {
   2479 			    tab_column = char_tabs[tab_index];
   2480 			    break;
   2481 			}
   2482 		    if (tab_index >= tab_count) {
   2483 			tab_base += char_tabs[tab_count - 1];
   2484 			tab_column = tab_index = 0;
   2485 		    }
   2486 		}
   2487 		else
   2488 		    tab_column += DEFAULT_TAB_SIZE;
   2489 	    }
   2490 	    column_number = (short)(tab_base + tab_column);
   2491 	}
   2492 	else
   2493 	    ++column_number;
   2494 	if (column_number >= 16384) {
   2495 	    column_number = 16383;
   2496 	    break;
   2497 	}
   2498     }
   2499 
   2500     return (column_number);
   2501 }
   2502 #endif /* OLDXAW */
   2503 
   2504 void
   2505 _XawTextSourceChanged(Widget w, XawTextPosition left, XawTextPosition right,
   2506 		      XawTextBlock *block, int lines _X_UNUSED)
   2507 {
   2508     TextWidget ctx = (TextWidget)w;
   2509     Widget src = ctx->text.source;
   2510     XawTextPosition update_from, update_to, top;
   2511     Boolean update_disabled;
   2512     int delta, line, line_from;
   2513 
   2514     if (left < ctx->text.old_insert) {
   2515 	XawTextPosition old_insert = ctx->text.old_insert;
   2516 
   2517 	if (right < ctx->text.old_insert)
   2518 	    old_insert -= right - left;
   2519 	else
   2520 	    old_insert = left;
   2521 
   2522 	ctx->text.insertPos = old_insert + block->length;
   2523     }
   2524 #ifndef OLDXAW
   2525     if (left <= ctx->text.lt.top) {
   2526 	if (left + block->length - (right - left) < ctx->text.lt.top) {
   2527 	    ctx->text.source_changed = SRC_CHANGE_BEFORE;
   2528 	    ctx->text.lt.base_line += lines;
   2529 	}
   2530 	else
   2531 	    ctx->text.source_changed = SRC_CHANGE_OVERLAP;
   2532     }
   2533     else
   2534 	ctx->text.source_changed = SRC_CHANGE_AFTER;
   2535 #endif
   2536 
   2537     update_from = left;
   2538     update_to = left + block->length;
   2539     update_to = SrcScan(src, update_to, XawstEOL, XawsdRight, 1, False);
   2540     delta = (int)(block->length - (right - left));
   2541     if (delta < 0)
   2542 	ctx->text.clear_to_eol = True;
   2543     if (update_to == update_from)
   2544 	++update_to;
   2545     update_disabled = ctx->text.update_disabled;
   2546     ctx->text.update_disabled = True;
   2547     ctx->text.lastPos = XawTextGetLastPosition(ctx);
   2548     top = ctx->text.lt.info[0].position;
   2549 
   2550     XawTextUnsetSelection((Widget)ctx);
   2551 
   2552     if (delta) {
   2553 	int i;
   2554 	XmuSegment *seg;
   2555 
   2556 	for (seg = ctx->text.update->segment; seg; seg = seg->next) {
   2557 	    if (seg->x1 > (int)left)
   2558 		break;
   2559 	    else if (seg->x2 > (int)left) {
   2560 		seg->x2 += delta;
   2561 		seg = seg->next;
   2562 		break;
   2563 	    }
   2564 	}
   2565 	for (; seg; seg = seg->next) {
   2566 	    seg->x1 += delta;
   2567 	    seg->x2 += delta;
   2568 	}
   2569 	XmuOptimizeScanline(ctx->text.update);
   2570 
   2571 	for (i = 0; i <= ctx->text.lt.lines; i++)
   2572 	    if (ctx->text.lt.info[i].position > left)
   2573 		break;
   2574 	for (; i <= ctx->text.lt.lines; i++)
   2575 	    ctx->text.lt.info[i].position += delta;
   2576     }
   2577 
   2578     if (top != ctx->text.lt.info[0].position) {
   2579 	line_from = line = 0;
   2580 	ctx->text.lt.top = top = SrcScan(src, ctx->text.lt.info[0].position,
   2581 					 XawstEOL, XawsdLeft, 1, False);
   2582 	update_from = top;
   2583     }
   2584     else {
   2585 	line_from = line = LineForPosition(ctx, update_from + delta);
   2586 	top = ctx->text.lt.info[line].position;
   2587     }
   2588 
   2589     if (line > 0 && ctx->text.wrap == XawtextWrapWord) {
   2590 	--line;
   2591 	top = ctx->text.lt.info[line].position;
   2592     }
   2593 
   2594     (void)_BuildLineTable(ctx, top, line);
   2595 
   2596     if (ctx->text.wrap == XawtextWrapWord) {
   2597 	if (line_from != LineForPosition(ctx, update_from)
   2598 	    || line_from != LineForPosition(ctx, update_to)) {
   2599 	    ctx->text.clear_to_eol = True;
   2600 	    update_from = SrcScan(src, update_from,
   2601 				  XawstWhiteSpace, XawsdLeft, 1, True);
   2602 	    if (update_to >= ctx->text.lastPos)
   2603 	    /* this is not an error, it just tells _BuildLineTable to
   2604 	     * clear to the bottom of the window. The value of update_to
   2605 	     * should not be > ctx->text.lastPos.
   2606 	     */
   2607 		++update_to;
   2608 	}
   2609     }
   2610     else if (!ctx->text.clear_to_eol) {
   2611 	if (LineForPosition(ctx, update_from)
   2612 	    != LineForPosition(ctx, update_to))
   2613 	    ctx->text.clear_to_eol = True;
   2614     }
   2615 
   2616     _XawTextNeedsUpdating(ctx, update_from, update_to);
   2617     ctx->text.update_disabled = update_disabled;
   2618 }
   2619 
   2620 /*
   2621  * Function:
   2622  *	_XawTextReplace
   2623  *
   2624  * Parameters:
   2625  *	ctx   - text widget
   2626  *	left  - left offset
   2627  *	right - right offset
   2628  *	block - text block
   2629  *
   2630  * Description:
   2631  *	  Replaces the text between left and right by the text in block.
   2632  *	  Does all the required calculations of offsets, and rebuild the
   2633  *	the line table, from the insertion point (or previous line, if
   2634  *	wrap mode is 'word').
   2635  *
   2636  * Returns:
   2637  *	XawEditDone     - success
   2638  *	any other value - error code
   2639  */
   2640 int
   2641 _XawTextReplace(TextWidget ctx, XawTextPosition left, XawTextPosition right,
   2642 		XawTextBlock *block)
   2643 {
   2644     Arg args[1];
   2645     Widget src;
   2646     XawTextEditType edit_mode;
   2647 
   2648     if (left == right && block->length == 0)
   2649 	return (XawEditDone);
   2650 
   2651     src = ctx->text.source;
   2652     XtSetArg(args[0], XtNeditType, &edit_mode);
   2653     XtGetValues(src, args, 1);
   2654 
   2655     if (edit_mode == XawtextAppend) {
   2656 	if (block->length == 0)
   2657 	    return (XawEditError);
   2658 	ctx->text.insertPos = ctx->text.lastPos;
   2659     }
   2660 
   2661 #ifndef OLDXAW
   2662     return (SrcReplace(src, left, right, block));
   2663 #else
   2664     if (SrcReplace(src, left, right, block) == XawEditDone) {
   2665 	_XawTextSourceChanged((Widget)ctx, left, right, block, 0);
   2666 
   2667 	return (XawEditDone);
   2668     }
   2669 
   2670     return (XawEditError);
   2671 #endif
   2672 }
   2673 
   2674 /*
   2675  * This routine will display text between two arbitrary source positions.
   2676  * In the event that this span contains highlighted text for the selection,
   2677  * only that portion will be displayed highlighted.
   2678  */
   2679 static void
   2680 OldDisplayText(Widget w, XawTextPosition left, XawTextPosition right)
   2681 {
   2682     static XmuSegment segment;
   2683     static XmuScanline next;
   2684     static XmuScanline scanline = {0, &segment, &next};
   2685     static XmuArea area = {&scanline};
   2686 
   2687     TextWidget ctx = (TextWidget)w;
   2688     int x, y, line;
   2689     XawTextPosition last;
   2690     XmuScanline *scan;
   2691     XmuSegment *seg;
   2692     XmuArea *clip = NULL;
   2693     Bool cleol = ctx->text.clear_to_eol;
   2694     Bool has_selection = ctx->text.s.right > ctx->text.s.left;
   2695     XawTextPosition start;
   2696 
   2697     left = left < ctx->text.lt.top ? ctx->text.lt.top : left;
   2698 
   2699     if (left > right || !LineAndXYForPosition(ctx, left, &line, &x, &y))
   2700 	return;
   2701 
   2702     last = XawTextGetLastPosition(ctx);
   2703     segment.x2 = (int)XtWidth(ctx) - ctx->text.r_margin.right;
   2704 
   2705     if (cleol)
   2706 	clip = XmuCreateArea();
   2707 
   2708     for (start = left;
   2709 	 start < right && line < ctx->text.lt.lines; line++) {
   2710 	XawTextPosition end, final;
   2711 
   2712 	if ((end = ctx->text.lt.info[line + 1].position) > right)
   2713 	    end = right;
   2714 
   2715 	final = end;
   2716 	if (end > last)
   2717 	    end = last;
   2718 
   2719 	if (end > start) {
   2720 	    if (!has_selection
   2721 		|| (start >= ctx->text.s.right || end <= ctx->text.s.left))
   2722 		_XawTextSinkDisplayText(ctx->text.sink, x, y, start, end, False);
   2723 	    else if (start >= ctx->text.s.left && end <= ctx->text.s.right)
   2724 		_XawTextSinkDisplayText(ctx->text.sink, x, y, start, end, True);
   2725 	    else {
   2726 		OldDisplayText(w, start, ctx->text.s.left);
   2727 		OldDisplayText(w, Max(start, ctx->text.s.left),
   2728 			       Min(end, ctx->text.s.right));
   2729 		OldDisplayText(w, ctx->text.s.right, end);
   2730 	    }
   2731 	}
   2732 
   2733 	x = ctx->text.left_margin;
   2734 	if (cleol) {
   2735 	    segment.x1 = (int)(ctx->text.lt.info[line].textWidth + (unsigned)x);
   2736 	    if (XmuValidSegment(&segment)) {
   2737 		scanline.y = y;
   2738 		next.y = ctx->text.lt.info[line + 1].y;
   2739 		XmuAreaOr(clip, &area);
   2740 	    }
   2741 	}
   2742 
   2743 	start = final;
   2744 	y = ctx->text.lt.info[line + 1].y;
   2745     }
   2746 
   2747     if (cleol)  {
   2748 	for (scan = clip->scanline; scan && scan->next; scan = scan->next)
   2749 	    for (seg = scan->segment; seg; seg = seg->next)
   2750 		SinkClearToBG(ctx->text.sink,
   2751 			      seg->x1, scan->y,
   2752 			      (unsigned)(seg->x2 - seg->x1),
   2753 			      (unsigned)(scan->next->y - scan->y));
   2754 	XmuDestroyArea(clip);
   2755     }
   2756 }
   2757 
   2758 #ifndef OLDXAW
   2759 /*ARGSUSED*/
   2760 static void
   2761 DisplayText(Widget w, XawTextPosition left, XawTextPosition right)
   2762 {
   2763     static XmuSegment segment;
   2764     static XmuScanline next;
   2765     static XmuScanline scanline = {0, &segment, &next};
   2766     static XmuArea area = {&scanline};
   2767 
   2768     TextWidget ctx = (TextWidget)w;
   2769     int y, line;
   2770     XawTextPosition lastPos;
   2771     Bool cleol = ctx->text.clear_to_eol;
   2772     Bool has_selection = ctx->text.s.right > ctx->text.s.left;
   2773     XawTextPaintList *paint_list;
   2774     XawTextPosition from;
   2775 
   2776     left = left < ctx->text.lt.top ? ctx->text.lt.top : left;
   2777 
   2778     if (left > right || !IsPositionVisible(ctx, left))
   2779 	return;
   2780 
   2781     line = LineForPosition(ctx, left);
   2782     y = ctx->text.lt.info[line].y;
   2783     segment.x2 = (int)XtWidth(ctx) - ctx->text.r_margin.right;
   2784     lastPos = XawTextGetLastPosition(ctx);
   2785 
   2786     paint_list = ((TextSinkObject)ctx->text.sink)->text_sink.paint;
   2787 
   2788     for (from = left;
   2789 	 from < right && line < ctx->text.lt.lines; line++) {
   2790 	XawTextPosition to = ctx->text.lt.info[line + 1].position;
   2791 
   2792 	if (to > right)
   2793 	    to = right;
   2794 
   2795 	if (to > lastPos)
   2796 	    to = lastPos;
   2797 
   2798 	if (from < to) {
   2799 	    if (!has_selection
   2800 		|| (from >= ctx->text.s.right || to <= ctx->text.s.left))
   2801 		XawTextSinkPreparePaint(ctx->text.sink, y, line, from, to, False);
   2802 	    else if (from >= ctx->text.s.left && to <= ctx->text.s.right)
   2803 		XawTextSinkPreparePaint(ctx->text.sink, y, line, from, to, True);
   2804 	    else {
   2805 		XawTextSinkPreparePaint(ctx->text.sink, y, line, from,
   2806 					ctx->text.s.left, False);
   2807 		XawTextSinkPreparePaint(ctx->text.sink, y, line,
   2808 					XawMax(from, ctx->text.s.left),
   2809 					XawMin(to, ctx->text.s.right), True);
   2810 		XawTextSinkPreparePaint(ctx->text.sink, y, line,
   2811 					ctx->text.s.right, to, False);
   2812 	    }
   2813 	}
   2814 
   2815 	if (cleol) {
   2816 	    segment.x1 = (int)(ctx->text.lt.info[line].textWidth + (unsigned)ctx->text.left_margin);
   2817 	    if (XmuValidSegment(&segment)) {
   2818 		scanline.y = y;
   2819 		next.y = ctx->text.lt.info[line + 1].y;
   2820 		XmuAreaOr(paint_list->clip, &area);
   2821 	    }
   2822 	}
   2823 	y = ctx->text.lt.info[line + 1].y;
   2824 	from = to;
   2825     }
   2826 
   2827     /* clear to the bottom of the window */
   2828     if (cleol && line >= ctx->text.lt.lines) {
   2829 	segment.x1 = ctx->text.left_margin;
   2830 	if (XmuValidSegment(&segment)) {
   2831 	    scanline.y = y;
   2832 	    next.y = (int)XtHeight(ctx) - (int)ctx->text.margin.bottom;
   2833 	    XmuAreaOr(paint_list->clip, &area);
   2834 	}
   2835     }
   2836 }
   2837 #endif
   2838 
   2839 /*
   2840  * This routine implements multi-click selection in a hardwired manner.
   2841  * It supports multi-click entity cycling (char, word, line, file) and mouse
   2842  * motion adjustment of the selected entity (i.e. select a word then, with
   2843  * button still down, adjust which word you really meant by moving the mouse).
   2844  * [NOTE: This routine is to be replaced by a set of procedures that
   2845  * will allows clients to implements a wide class of draw through and
   2846  * multi-click selection user interfaces.]
   2847  */
   2848 static void
   2849 DoSelection(TextWidget ctx, XawTextPosition pos, Time time, Bool motion)
   2850 {
   2851     XawTextPosition newLeft, newRight;
   2852     XawTextSelectType newType;
   2853     Widget src = ctx->text.source;
   2854 
   2855     if (motion)
   2856 	newType = ctx->text.s.type;
   2857     else {
   2858 	if ((labs((long) time - (long) ctx->text.lasttime) < MULTI_CLICK_TIME)
   2859 	    && (pos >= ctx->text.s.left && pos <= ctx->text.s.right)) {
   2860 	    XawTextSelectType *sarray = ctx->text.sarray;
   2861 
   2862 	    for (; *sarray != XawselectNull && *sarray != ctx->text.s.type;
   2863 		 sarray++)
   2864 		;
   2865 	    if (*sarray == XawselectNull)
   2866 		newType = *(ctx->text.sarray);
   2867 	    else {
   2868 		newType = *(sarray + 1);
   2869 		if (newType == XawselectNull)
   2870 		    newType = *(ctx->text.sarray);
   2871 	    }
   2872 	}
   2873 	else		/* single-click event */
   2874 	    newType = *(ctx->text.sarray);
   2875 
   2876 	ctx->text.lasttime = time;
   2877     }
   2878     switch (newType) {
   2879 	case XawselectPosition:
   2880 	    newLeft = newRight = pos;
   2881 	    break;
   2882 	case XawselectChar:
   2883 	    newLeft = pos;
   2884 	    newRight = SrcScan(src, pos, XawstPositions, XawsdRight, 1, False);
   2885 	    break;
   2886 	case XawselectWord:
   2887 	case XawselectParagraph:
   2888 	case XawselectAlphaNumeric: {
   2889 	    XawTextScanType stype;
   2890 
   2891 	    if (newType == XawselectWord)
   2892 		stype = XawstWhiteSpace;
   2893 	    else if (newType == XawselectParagraph)
   2894 		stype = XawstParagraph;
   2895 	    else
   2896 		stype = XawstAlphaNumeric;
   2897 
   2898 	    /*
   2899 	     * Somewhat complicated, but basically I treat the space between
   2900 	     * two objects as another object.  The object that I am currently
   2901 	     * in then becomes the end of the selection.
   2902 	     *
   2903 	     * Chris Peterson - 4/19/90.
   2904 	     */
   2905 	    newRight = SrcScan(ctx->text.source, pos, stype,
   2906 			       XawsdRight, 1, False);
   2907 	    newRight = SrcScan(ctx->text.source, newRight, stype,
   2908 			       XawsdLeft, 1, False);
   2909 
   2910 	    if (pos != newRight)
   2911 		newLeft = SrcScan(ctx->text.source, pos, stype,
   2912 				  XawsdLeft, 1, False);
   2913 	    else
   2914 		newLeft = pos;
   2915 
   2916 	    newLeft =SrcScan(ctx->text.source, newLeft, stype,
   2917 			     XawsdRight, 1, False);
   2918 
   2919 	    if (newLeft > newRight) {
   2920 		XawTextPosition temp = newLeft;
   2921 		newLeft = newRight;
   2922 		newRight = temp;
   2923 	    }
   2924 	}   break;
   2925 	case XawselectLine:
   2926 	    newLeft = SrcScan(src, pos, XawstEOL, XawsdLeft, 1, False);
   2927 	    newRight = SrcScan(src, pos, XawstEOL, XawsdRight, 1, False);
   2928 	    break;
   2929 	case XawselectAll:
   2930 	    newLeft = SrcScan(src, pos, XawstAll, XawsdLeft, 1, False);
   2931 	    newRight = SrcScan(src, pos, XawstAll, XawsdRight, 1, False);
   2932 	    break;
   2933 	default:
   2934 	    XtAppWarning(XtWidgetToApplicationContext((Widget) ctx),
   2935 			 "Text Widget: empty selection array.");
   2936 	    return;
   2937     }
   2938 
   2939     if (newLeft != ctx->text.s.left || newRight != ctx->text.s.right
   2940 	|| newType != ctx->text.s.type) {
   2941 	ModifySelection(ctx, newLeft, newRight);
   2942 	if (pos - ctx->text.s.left < ctx->text.s.right - pos)
   2943 	    ctx->text.insertPos = newLeft;
   2944 	else
   2945 	    ctx->text.insertPos = newRight;
   2946 	ctx->text.s.type = newType;
   2947     }
   2948     if (!motion) {	/* setup so we can freely mix select extend calls*/
   2949 	ctx->text.origSel.type = ctx->text.s.type;
   2950 	ctx->text.origSel.left = ctx->text.s.left;
   2951 	ctx->text.origSel.right = ctx->text.s.right;
   2952 
   2953 	if (pos >= ctx->text.s.left + (ctx->text.s.right - ctx->text.s.left) / 2)
   2954 	    ctx->text.extendDir = XawsdRight;
   2955 	else
   2956 	    ctx->text.extendDir = XawsdLeft;
   2957     }
   2958 }
   2959 
   2960 /*
   2961  * This routine implements extension of the currently selected text in
   2962  * the "current" mode (i.e. char word, line, etc.). It worries about
   2963  * extending from either end of the selection and handles the case when you
   2964  * cross through the "center" of the current selection (e.g. switch which
   2965  * end you are extending!).
   2966  */
   2967 static void
   2968 ExtendSelection(TextWidget ctx, XawTextPosition pos, Bool motion)
   2969 {
   2970     XawTextScanDirection dir;
   2971 
   2972     if (!motion) {	/* setup for extending selection */
   2973 	if (ctx->text.s.left == ctx->text.s.right) /* no current selection. */
   2974 	    ctx->text.s.left = ctx->text.s.right = ctx->text.insertPos;
   2975 	else {
   2976 	    ctx->text.origSel.left = ctx->text.s.left;
   2977 	    ctx->text.origSel.right = ctx->text.s.right;
   2978 	}
   2979 
   2980 	ctx->text.origSel.type = ctx->text.s.type;
   2981 
   2982 	if (pos >= ctx->text.s.left + (ctx->text.s.right - ctx->text.s.left) / 2)
   2983 	    ctx->text.extendDir = XawsdRight;
   2984 	else
   2985 	    ctx->text.extendDir = XawsdLeft;
   2986     }
   2987     else	/* check for change in extend direction */
   2988 	if ((ctx->text.extendDir == XawsdRight &&
   2989 	     pos <= ctx->text.origSel.left) ||
   2990 	    (ctx->text.extendDir == XawsdLeft &&
   2991 	     pos >= ctx->text.origSel.right)) {
   2992 	    ctx->text.extendDir = (ctx->text.extendDir == XawsdRight) ?
   2993 		XawsdLeft : XawsdRight;
   2994 	    ModifySelection(ctx, ctx->text.origSel.left, ctx->text.origSel.right);
   2995 	}
   2996 
   2997     dir = ctx->text.extendDir;
   2998     switch (ctx->text.s.type) {
   2999 	case XawselectWord:
   3000 	case XawselectParagraph:
   3001 	case XawselectAlphaNumeric: {
   3002 	    XawTextPosition left_pos, right_pos;
   3003 	    XawTextScanType stype;
   3004 
   3005 	    if (ctx->text.s.type == XawselectWord)
   3006 	        stype = XawstWhiteSpace;
   3007 	    else if (ctx->text.s.type == XawselectParagraph)
   3008 	        stype = XawstParagraph;
   3009 	    else
   3010 	        stype = XawstAlphaNumeric;
   3011 
   3012 	    /*
   3013 	     * Somewhat complicated, but basically I treat the space between
   3014 	     * two objects as another object.  The object that I am currently
   3015 	     * in then becomes the end of the selection.
   3016 	     *
   3017 	     * Chris Peterson - 4/19/90.
   3018 	     */
   3019 	    right_pos = SrcScan(ctx->text.source, pos, stype,
   3020 				XawsdRight, 1, False);
   3021 	    right_pos =SrcScan(ctx->text.source, right_pos, stype,
   3022 			       XawsdLeft, 1, False);
   3023 
   3024 	    if (pos != right_pos)
   3025 		left_pos = SrcScan(ctx->text.source, pos, stype,
   3026 				   XawsdLeft, 1, False);
   3027 	    else
   3028 		left_pos = pos;
   3029 
   3030 	    left_pos =SrcScan(ctx->text.source, left_pos, stype,
   3031 			      XawsdRight, 1, False);
   3032 
   3033 	    if (dir == XawsdLeft)
   3034 		pos = Min(left_pos, right_pos);
   3035 	    else	/* dir == XawsdRight */
   3036 		pos = Max(left_pos, right_pos);
   3037 	}   break;
   3038 	case XawselectLine:
   3039 	    pos = SrcScan(ctx->text.source, pos, XawstEOL,
   3040 			  dir, 1, dir == XawsdRight);
   3041 	    break;
   3042 	case XawselectAll:
   3043 	    pos = ctx->text.insertPos;
   3044 	    /*FALLTHROUGH*/
   3045 	case XawselectPosition:
   3046 	default:
   3047 	    break;
   3048     }
   3049 
   3050     if (dir == XawsdRight)
   3051 	ModifySelection(ctx, ctx->text.s.left, pos);
   3052     else
   3053 	ModifySelection(ctx, pos, ctx->text.s.right);
   3054 
   3055     ctx->text.insertPos = pos;
   3056 }
   3057 
   3058 /*
   3059  * Function:
   3060  *	_XawTextClearAndCenterDisplay
   3061  *
   3062  * Parameters:
   3063  *	ctx - text widget
   3064  *
   3065  * Description:
   3066  *	  Redraws the display with the cursor in insert point
   3067  *		     centered vertically.
   3068  */
   3069 void
   3070 _XawTextClearAndCenterDisplay(TextWidget ctx)
   3071 {
   3072     int left_margin = ctx->text.left_margin;
   3073     Bool visible = IsPositionVisible(ctx, ctx->text.insertPos);
   3074 
   3075     _XawTextShowPosition(ctx);
   3076 
   3077     if (XtIsRealized((Widget)ctx) && visible &&
   3078 	left_margin == ctx->text.left_margin) {
   3079 	int insert_line = LineForPosition(ctx, ctx->text.insertPos);
   3080 	int scroll_by = insert_line - (ctx->text.lt.lines >> 1);
   3081 	Boolean clear_to_eol;
   3082 
   3083 	XawTextScroll(ctx, scroll_by, 0);
   3084 	SinkClearToBG(ctx->text.sink, 0, 0, XtWidth(ctx), XtHeight(ctx));
   3085 	ClearWindow(ctx);
   3086 	clear_to_eol = ctx->text.clear_to_eol;
   3087 	ctx->text.clear_to_eol = False;
   3088 	FlushUpdate(ctx);
   3089 	ctx->text.clear_to_eol = clear_to_eol;
   3090     }
   3091 }
   3092 
   3093 /*
   3094  * Internal redisplay entire window
   3095  * Legal to call only if widget is realized
   3096  */
   3097 static void
   3098 DisplayTextWindow(Widget w)
   3099 {
   3100     TextWidget ctx = (TextWidget)w;
   3101 
   3102     _XawTextBuildLineTable(ctx, ctx->text.lt.top, False);
   3103     ClearWindow(ctx);
   3104 }
   3105 
   3106 static void
   3107 TextSinkResize(Widget w)
   3108 {
   3109     if (w && XtClass(w)->core_class.resize)
   3110 	XtClass(w)->core_class.resize(w);
   3111 }
   3112 
   3113 /* ARGSUSED */
   3114 void
   3115 _XawTextCheckResize(TextWidget ctx _X_UNUSED)
   3116 {
   3117     return;
   3118 }
   3119 
   3120 /*
   3121  * Converts (params, num_params) to a list of atoms & caches the
   3122  * list in the TextWidget instance.
   3123  */
   3124 Atom *
   3125 _XawTextSelectionList(TextWidget ctx, String *list, Cardinal nelems)
   3126 {
   3127     Atom *sel = ctx->text.s.selections;
   3128     Display *dpy = XtDisplay((Widget)ctx);
   3129     int n;
   3130 
   3131     if (nelems > (Cardinal)ctx->text.s.array_size) {
   3132 	sel = (Atom *)XtRealloc((char *)sel, (Cardinal)(sizeof(Atom) * (size_t)nelems));
   3133 	ctx->text.s.array_size = (int)nelems;
   3134 	ctx->text.s.selections = sel;
   3135     }
   3136     for (n = (int)nelems; --n >= 0; sel++, list++)
   3137 	*sel = XInternAtom(dpy, *list, False);
   3138     ctx->text.s.atom_count = (int)nelems;
   3139 
   3140     return (ctx->text.s.selections);
   3141 }
   3142 
   3143 /*
   3144  * Function:
   3145  *	SetSelection
   3146  *
   3147  * Parameters:
   3148  *	ctx	   - text widget
   3149  *	defaultSel - default selection
   3150  *	l	   - left and right ends of the selection
   3151  *	r	   - ""
   3152  *	list	   - the selection list (as strings).
   3153  *	nelems	   - ""
   3154  *
   3155  * Description:
   3156  *	Sets the current selection.
   3157  *
   3158  * Note:
   3159  *	if (ctx->text.s.left >= ctx->text.s.right) then the selection is unset
   3160  */
   3161 void
   3162 _XawTextSetSelection(TextWidget ctx, XawTextPosition l, XawTextPosition r,
   3163 		     String *list, Cardinal nelems)
   3164 {
   3165     if (nelems == 1 && !strcmp (list[0], "none"))
   3166 	return;
   3167     if (nelems == 0) {
   3168 	static String defaultSel = "PRIMARY";
   3169 	list = &defaultSel;
   3170 	nelems = 1;
   3171     }
   3172     _SetSelection(ctx, l, r, _XawTextSelectionList(ctx, list, nelems), nelems);
   3173 }
   3174 
   3175 /*
   3176  * Function:
   3177  *	ModifySelection
   3178  *
   3179  * Parameters:
   3180  *	ctx   - text widget
   3181  *	left  - left and right ends of the selection
   3182  *	right - ""
   3183  *
   3184  * Description:
   3185  *	Modifies the current selection.
   3186  *
   3187  * Note:
   3188  *	if (ctx->text.s.left >= ctx->text.s.right) then the selection is unset
   3189  */
   3190 static void
   3191 ModifySelection(TextWidget ctx, XawTextPosition left, XawTextPosition right)
   3192 {
   3193     if (left == right)
   3194 	ctx->text.insertPos = left;
   3195     _SetSelection(ctx, left, right, NULL, 0);
   3196 }
   3197 
   3198 /*
   3199  * This routine is used to perform various selection functions. The goal is
   3200  * to be able to specify all the more popular forms of draw-through and
   3201  * multi-click selection user interfaces from the outside.
   3202  */
   3203 void
   3204 _XawTextAlterSelection(TextWidget ctx, XawTextSelectionMode mode,
   3205 		       XawTextSelectionAction action, String *params,
   3206 		       Cardinal *num_params)
   3207 {
   3208     XawTextPosition position;
   3209     Boolean flag;
   3210 
   3211     /*
   3212      * This flag is used by TextPop.c:DoReplace() to determine if the selection
   3213      * is okay to use, or if it has been modified.
   3214      */
   3215     if (ctx->text.search != NULL)
   3216 	ctx->text.search->selection_changed = True;
   3217 
   3218     position = PositionForXY(ctx, (int) ctx->text.ev_x, (int) ctx->text.ev_y);
   3219 
   3220     flag = (action != XawactionStart);
   3221     if (mode == XawsmTextSelect)
   3222 	DoSelection(ctx, position, ctx->text.time, flag);
   3223     else		/* mode == XawsmTextExtend */
   3224 	ExtendSelection (ctx, position, flag);
   3225 
   3226     if (action == XawactionEnd)
   3227 	_XawTextSetSelection(ctx, ctx->text.s.left, ctx->text.s.right,
   3228 			     params, *num_params);
   3229 }
   3230 
   3231 /*
   3232  * Function:
   3233  *	UpdateTextInRectangle
   3234  *
   3235  * Parameters:
   3236  *	ctx  - the text widget
   3237  *	rect - rectangle
   3238  *
   3239  * Description:
   3240  *	Updates the text in the given rectangle
   3241  */
   3242 static void
   3243 UpdateTextInRectangle(TextWidget ctx, XRectangle *rect)
   3244 {
   3245     XawTextLineTable *lt;
   3246     int line, y1, y2, x2;
   3247 
   3248     y1 = rect->y;
   3249     y2 = y1 + rect->height;
   3250     x2 = rect->x + rect->width;
   3251 
   3252     for (line = 0, lt = &ctx->text.lt; line < lt->lines; line++)
   3253 	if (lt->info[line + 1].y > y1)
   3254 	    break;
   3255     for (; line <= lt->lines; line++) {
   3256 	if (lt->info[line].y > y2)
   3257 	    break;
   3258 	UpdateTextInLine(ctx, line, rect->x, x2);
   3259     }
   3260 }
   3261 
   3262 /*
   3263  * This routine processes all "expose region" XEvents. In general, its job
   3264  * is to the best job at minimal re-paint of the text, displayed in the
   3265  * window, that it can.
   3266  */
   3267 /* ARGSUSED */
   3268 static void
   3269 XawTextExpose(Widget w, XEvent *event, Region region)
   3270 {
   3271     TextWidget ctx = (TextWidget)w;
   3272     Boolean clear_to_eol;
   3273     XRectangle expose;
   3274 
   3275     if (event->type == Expose) {
   3276 	expose.x = (short)event->xexpose.x;
   3277 	expose.y = (short)event->xexpose.y;
   3278 	expose.width = (unsigned short)event->xexpose.width;
   3279 	expose.height = (unsigned short)event->xexpose.height;
   3280     }
   3281     else if (event->type == GraphicsExpose) {
   3282 	expose.x = (short)event->xgraphicsexpose.x;
   3283 	expose.y = (short)event->xgraphicsexpose.y;
   3284 	expose.width = (unsigned short)event->xgraphicsexpose.width;
   3285 	expose.height = (unsigned short)event->xgraphicsexpose.height;
   3286     }
   3287     else
   3288 	return;
   3289 
   3290     _XawTextPrepareToUpdate(ctx);
   3291 
   3292     if (Superclass->core_class.expose)
   3293 	(*Superclass->core_class.expose)(w, event, region);
   3294 
   3295     clear_to_eol = ctx->text.clear_to_eol;
   3296     ctx->text.clear_to_eol = False;
   3297 
   3298     UpdateTextInRectangle(ctx, &expose);
   3299     XawTextSinkGetCursorBounds(ctx->text.sink, &expose);
   3300     UpdateTextInRectangle(ctx, &expose);
   3301     SinkClearToBG(ctx->text.sink, expose.x, expose.y,
   3302 		  expose.width, expose.height);
   3303     _XawTextExecuteUpdate(ctx);
   3304     ctx->text.clear_to_eol = clear_to_eol;
   3305 }
   3306 
   3307 /*
   3308  * This routine does all setup required to synchronize batched screen updates
   3309  */
   3310 void
   3311 _XawTextPrepareToUpdate(TextWidget ctx)
   3312 {
   3313     if (ctx->text.old_insert < 0) {
   3314 	InsertCursor((Widget)ctx, XawisOff);
   3315 	ctx->text.showposition = False;
   3316 	ctx->text.old_insert = ctx->text.insertPos;
   3317 	ctx->text.clear_to_eol = False;
   3318 #ifndef OLDXAW
   3319 	ctx->text.source_changed = SRC_CHANGE_NONE;
   3320 #endif
   3321     }
   3322 }
   3323 
   3324 /*
   3325  * This is a private utility routine used by _XawTextExecuteUpdate. It
   3326  * processes all the outstanding update requests and merges update
   3327  * ranges where possible.
   3328  */
   3329 static void
   3330 FlushUpdate(TextWidget ctx)
   3331 {
   3332     XmuSegment *seg;
   3333     void (*display_text)(Widget, XawTextPosition, XawTextPosition);
   3334 
   3335     if (XtIsRealized((Widget)ctx)) {
   3336 	ctx->text.s.right = XawMin(ctx->text.s.right, ctx->text.lastPos);
   3337 	ctx->text.s.left = XawMin(ctx->text.s.left, ctx->text.s.right);
   3338 
   3339 #ifndef OLDXAW
   3340 	if (XawTextSinkBeginPaint(ctx->text.sink) == False)
   3341 #endif
   3342 	    display_text = OldDisplayText;
   3343 #ifndef OLDXAW
   3344 	else
   3345 	    display_text = DisplayText;
   3346 #endif
   3347 	for (seg = ctx->text.update->segment; seg; seg = seg->next)
   3348 	    (*display_text)((Widget)ctx,
   3349 			    (XawTextPosition)seg->x1,
   3350 			    (XawTextPosition)seg->x2);
   3351 #ifndef OLDXAW
   3352 	if (display_text != OldDisplayText) {
   3353 	    XawTextSinkDoPaint(ctx->text.sink);
   3354 	    XawTextSinkEndPaint(ctx->text.sink);
   3355 	}
   3356 #endif
   3357     }
   3358     (void)XmuScanlineXor(ctx->text.update, ctx->text.update);
   3359 }
   3360 
   3361 static int
   3362 CountLines(TextWidget ctx, XawTextPosition left, XawTextPosition right)
   3363 {
   3364     if (ctx->text.wrap == XawtextWrapNever || left >= right)
   3365 	return (1);
   3366     else {
   3367 	int dim, lines = 0, wwidth = GetMaxTextWidth(ctx);
   3368 
   3369 	while (left < right) {
   3370 	    XawTextPosition tmp = left;
   3371 
   3372 	    XawTextSinkFindPosition(ctx->text.sink, left,
   3373 				    ctx->text.left_margin,
   3374 				    wwidth, ctx->text.wrap == XawtextWrapWord,
   3375 				    &left, &dim, &dim);
   3376 	    ++lines;
   3377 	    if (tmp == left)
   3378 	      ++left;
   3379 	}
   3380 
   3381 	return (lines);
   3382     }
   3383     /*NOTREACHED*/
   3384 }
   3385 
   3386 static int
   3387 GetMaxTextWidth(TextWidget ctx)
   3388 {
   3389     XRectangle cursor;
   3390     int width;
   3391 
   3392     XawTextSinkGetCursorBounds(ctx->text.sink, &cursor);
   3393     width = (int)XtWidth(ctx) - RHMargins(ctx) - cursor.width;
   3394 
   3395     return (XawMax(0, width));
   3396 }
   3397 
   3398 /*
   3399  * Function:
   3400  *	_XawTextShowPosition
   3401  *
   3402  * Parameters:
   3403  *	ctx - the text widget to show the position
   3404  *
   3405  * Description:
   3406  *	  Makes sure the text cursor visible, scrolling the text window
   3407  *	if required.
   3408  */
   3409 void
   3410 _XawTextShowPosition(TextWidget ctx)
   3411 {
   3412     /*
   3413      * Variable scroll is used to avoid scanning large files to calculate
   3414      * line offsets
   3415      */
   3416     int hpixels, vlines;
   3417     XawTextPosition first, last, top, tmp;
   3418     Bool visible, scroll;
   3419 
   3420     if (!XtIsRealized((Widget)ctx))
   3421 	return;
   3422 
   3423     /*
   3424      * Checks if a horizontal scroll is required
   3425      */
   3426     if (ctx->text.wrap == XawtextWrapNever) {
   3427 	int x, vwidth, distance, dim;
   3428 	XRectangle rect;
   3429 
   3430 	vwidth = (int)XtWidth(ctx) - RHMargins(ctx);
   3431 	last = SrcScan(ctx->text.source, ctx->text.insertPos,
   3432 		       XawstEOL, XawsdLeft, 1, False);
   3433 	XawTextSinkFindDistance(ctx->text.sink, last,
   3434 				ctx->text.left_margin,
   3435 				ctx->text.insertPos,
   3436 				&distance, &first, &dim);
   3437 	XawTextSinkGetCursorBounds(ctx->text.sink, &rect);
   3438 	x = ctx->text.left_margin - ctx->text.r_margin.left;
   3439 
   3440 	if (x + distance + rect.width > vwidth)
   3441 	    hpixels = x + distance + rect.width - vwidth + (vwidth >> 2);
   3442 	else if (x + distance < 0)
   3443 	    hpixels = x + distance - (vwidth >> 2);
   3444 	else
   3445 	    hpixels = 0;
   3446     }
   3447     else
   3448 	hpixels = 0;
   3449 
   3450     visible = IsPositionVisible(ctx, ctx->text.insertPos);
   3451 
   3452     /*
   3453      * If the cursor is already visible
   3454      */
   3455     if (!hpixels && visible)
   3456 	return;
   3457 
   3458     scroll = ctx->core.background_pixmap == XtUnspecifiedPixmap && !hpixels;
   3459     vlines = 0;
   3460     first = ctx->text.lt.top;
   3461 
   3462     /*
   3463      * Needs to scroll the text window
   3464      */
   3465     if (visible)
   3466       top = ctx->text.lt.top;
   3467     else {
   3468         top = SrcScan(ctx->text.source, ctx->text.insertPos,
   3469 		      XawstEOL, XawsdLeft, 1, False);
   3470 
   3471 	/*
   3472 	 * Finds the nearest left position from ctx->text.insertPos
   3473 	 */
   3474 	if (ctx->text.wrap != XawtextWrapNever) {
   3475 	    int dim, vwidth = GetMaxTextWidth(ctx);
   3476 
   3477 	    last = top;
   3478 	    /*CONSTCOND*/
   3479 	    while (1) {
   3480 		tmp = last;
   3481 		XawTextSinkFindPosition(ctx->text.sink, last,
   3482 					ctx->text.left_margin, vwidth,
   3483 					ctx->text.wrap == XawtextWrapWord,
   3484 					&last, &dim, &dim);
   3485 		if (last == tmp)
   3486 		    ++last;
   3487 		if (last <= ctx->text.insertPos)
   3488 		    top = last;
   3489 		else
   3490 		    break;
   3491 	    }
   3492 	}
   3493     }
   3494 
   3495     if (scroll) {
   3496 	if (ctx->text.insertPos < first) {	/* Scroll Down */
   3497 	    while (first > top) {
   3498 		last = first;
   3499 		first = SrcScan(ctx->text.source, first,
   3500 				XawstEOL, XawsdLeft, 2, False);
   3501 		vlines -= CountLines(ctx, first, last);
   3502 		if (-vlines >= ctx->text.lt.lines) {
   3503 		    scroll = False;
   3504 		    break;
   3505 		}
   3506 	    }
   3507 	}
   3508 	else if (!visible) {			/* Scroll Up */
   3509 	    while (first < top) {
   3510 		last = first;
   3511 		first = SrcScan(ctx->text.source, first,
   3512 				XawstEOL, XawsdRight, 1, True);
   3513 		vlines += CountLines(ctx, last, first);
   3514 		if (vlines > ctx->text.lt.lines) {
   3515 		    scroll = False;
   3516 		    break;
   3517 		}
   3518 	    }
   3519 	}
   3520 	else
   3521 	    scroll = False;
   3522     }
   3523 
   3524     /*
   3525      * If a portion of the text that will be scrolled is visible
   3526      */
   3527     if (scroll)
   3528 	XawTextScroll(ctx, vlines ? vlines - (ctx->text.lt.lines >> 1) : 0, 0);
   3529     /*
   3530      * Else redraw the entire text window
   3531      */
   3532     else {
   3533 	ctx->text.left_margin -= hpixels;
   3534 	if (ctx->text.left_margin > ctx->text.r_margin.left)
   3535 	    ctx->text.left_margin = ctx->text.margin.left =
   3536 		ctx->text.r_margin.left;
   3537 
   3538 	if (!visible) {
   3539 	    vlines = ctx->text.lt.lines >> 1;
   3540 	    if (vlines)
   3541 		top = SrcScan(ctx->text.source, ctx->text.insertPos,
   3542 			      XawstEOL, XawsdLeft, vlines + 1, False);
   3543 
   3544 	    if (ctx->text.wrap != XawtextWrapNever) {
   3545 		int dim;
   3546 		int n_lines = CountLines(ctx, top, ctx->text.insertPos);
   3547 		int vwidth = GetMaxTextWidth(ctx);
   3548 
   3549 		while (n_lines-- > vlines) {
   3550 		    tmp = top;
   3551 		    XawTextSinkFindPosition(ctx->text.sink, top,
   3552 					    ctx->text.left_margin,
   3553 					    vwidth,
   3554 					    ctx->text.wrap == XawtextWrapWord,
   3555 					    &top, &dim, &dim);
   3556 		    if (tmp == top)
   3557 			++top;
   3558 		}
   3559 	    }
   3560 	    _XawTextBuildLineTable(ctx, top, True);
   3561 	}
   3562 	else
   3563 	    ClearWindow(ctx);
   3564     }
   3565     ctx->text.clear_to_eol = True;
   3566 }
   3567 
   3568 #ifndef OLDXAW
   3569 static int
   3570 ResolveLineNumber(TextWidget ctx)
   3571 {
   3572     int line_number = ctx->text.lt.base_line;
   3573     XawTextPosition position = ctx->text.lt.top;
   3574 
   3575     if (ctx->text.lt.base_line < 1)
   3576 	return (ctx->text.line_number);
   3577 
   3578     if (ctx->text.wrap == XawtextWrapNever
   3579 	&& IsPositionVisible(ctx, ctx->text.insertPos))
   3580 	line_number += LineForPosition(ctx, ctx->text.insertPos);
   3581     else if (position < ctx->text.insertPos) {
   3582 	while (position < ctx->text.insertPos) {
   3583 	    position = SrcScan(ctx->text.source, position,
   3584 			       XawstEOL, XawsdRight, 1, True);
   3585 	    if (position <= ctx->text.insertPos) {
   3586 		++line_number;
   3587 		if (position == ctx->text.lastPos) {
   3588 		    line_number -= !_XawTextSourceNewLineAtEOF(ctx->text.source);
   3589 		    break;
   3590 		}
   3591 	    }
   3592 	}
   3593     }
   3594     else if (position > ctx->text.insertPos) {
   3595 	while (position > ctx->text.insertPos) {
   3596 	    position = SrcScan(ctx->text.source, position,
   3597 			       XawstEOL, XawsdLeft, 1, False);
   3598 	    if (--position >= ctx->text.insertPos)
   3599 		--line_number;
   3600 	}
   3601     }
   3602 
   3603     return (line_number);
   3604 }
   3605 #endif
   3606 
   3607 /*
   3608  * This routine causes all batched screen updates to be performed
   3609  */
   3610 void
   3611 _XawTextExecuteUpdate(TextWidget ctx)
   3612 {
   3613     if (ctx->text.update_disabled || ctx->text.old_insert < 0)
   3614 	return;
   3615 
   3616     if(ctx->text.old_insert != ctx->text.insertPos || ctx->text.showposition)
   3617 	_XawTextShowPosition(ctx);
   3618 
   3619     FlushUpdate(ctx);
   3620     InsertCursor((Widget)ctx, XawisOn);
   3621     ctx->text.old_insert = -1;
   3622 #ifndef OLDXAW
   3623     _XawTextSetLineAndColumnNumber(ctx, False);
   3624 #endif
   3625 }
   3626 
   3627 static void
   3628 XawTextDestroy(Widget w)
   3629 {
   3630     TextWidget ctx = (TextWidget)w;
   3631 
   3632     DestroyHScrollBar(ctx);
   3633     DestroyVScrollBar(ctx);
   3634 
   3635     XtFree((char *)ctx->text.s.selections);
   3636     XtFree((char *)ctx->text.lt.info);
   3637     XtFree((char *)ctx->text.search);
   3638     XmuDestroyScanline(ctx->text.update);
   3639     XtReleaseGC((Widget)ctx, ctx->text.gc);
   3640 }
   3641 
   3642 /*
   3643  * by the time we are managed (and get this far) we had better
   3644  * have both a source and a sink
   3645  */
   3646 static void
   3647 XawTextResize(Widget w)
   3648 {
   3649     TextWidget ctx = (TextWidget)w;
   3650 
   3651     PositionVScrollBar(ctx);
   3652     PositionHScrollBar(ctx);
   3653     TextSinkResize(ctx->text.sink);
   3654 
   3655     ctx->text.showposition = True;
   3656     _XawTextBuildLineTable(ctx, ctx->text.lt.top, True);
   3657 }
   3658 
   3659 /*
   3660  * This routine allow the application program to Set attributes.
   3661  */
   3662 /*ARGSUSED*/
   3663 static Boolean
   3664 XawTextSetValues(Widget current, Widget request _X_UNUSED, Widget cnew,
   3665 		 ArgList args, Cardinal *num_args)
   3666 {
   3667     TextWidget oldtw = (TextWidget)current;
   3668     TextWidget newtw = (TextWidget)cnew;
   3669     Boolean redisplay = False;
   3670     Boolean display_caret = newtw->text.display_caret;
   3671 #ifndef OLDXAW
   3672     Boolean show_lc = False;
   3673 #endif
   3674 
   3675     newtw->text.display_caret = oldtw->text.display_caret;
   3676     _XawTextPrepareToUpdate(newtw);
   3677     newtw->text.display_caret = display_caret;
   3678 
   3679     if (oldtw->text.r_margin.left != newtw->text.r_margin.left) {
   3680 	newtw->text.left_margin = newtw->text.margin.left =
   3681 	    newtw->text.r_margin.left;
   3682 	if (newtw->text.vbar != NULL) {
   3683 	    newtw->text.left_margin += XtWidth(newtw->text.vbar) +
   3684 		XtBorderWidth(newtw->text.vbar);
   3685 	}
   3686 	redisplay = True;
   3687     }
   3688 
   3689     if (oldtw->text.scroll_vert != newtw->text.scroll_vert) {
   3690 	if (newtw->text.scroll_vert == XawtextScrollAlways)
   3691 	    CreateVScrollBar(newtw);
   3692 	else
   3693 	    DestroyVScrollBar(newtw);
   3694 
   3695 	redisplay = True;
   3696     }
   3697 
   3698     if (oldtw->text.r_margin.bottom != newtw->text.r_margin.bottom) {
   3699 	newtw->text.margin.bottom = newtw->text.r_margin.bottom;
   3700 	if (newtw->text.hbar != NULL)
   3701 	    newtw->text.margin.bottom = (Position)(newtw->text.margin.bottom
   3702 					 + (newtw->text.hbar->core.height
   3703 					 + newtw->text.hbar->core.border_width));
   3704 	redisplay = True;
   3705     }
   3706 
   3707     if (oldtw->text.scroll_horiz != newtw->text.scroll_horiz) {
   3708 	if (newtw->text.scroll_horiz == XawtextScrollAlways)
   3709 	    CreateHScrollBar(newtw);
   3710 	else
   3711 	    DestroyHScrollBar(newtw);
   3712 
   3713 	redisplay = True;
   3714     }
   3715 
   3716     if (oldtw->text.source != newtw->text.source) {
   3717 #ifndef OLDXAW
   3718 	show_lc = True;
   3719 	_XawSourceRemoveText(oldtw->text.source, cnew,
   3720 			     oldtw->text.source &&
   3721 			     XtParent(oldtw->text.source) == cnew);
   3722 	_XawSourceAddText(newtw->text.source, cnew);
   3723 #endif
   3724 	_XawTextSetSource((Widget)newtw, newtw->text.source, newtw->text.lt.top,
   3725 			  newtw->text.insertPos);
   3726     }
   3727 
   3728     newtw->text.redisplay_needed = False;
   3729     XtSetValues((Widget)newtw->text.source, args, *num_args);
   3730     XtSetValues((Widget)newtw->text.sink, args, *num_args);
   3731 
   3732     if (oldtw->text.wrap != newtw->text.wrap
   3733 	|| oldtw->text.lt.top != newtw->text.lt.top
   3734 	|| oldtw->text.insertPos != newtw->text.insertPos
   3735 	|| oldtw->text.r_margin.right != newtw->text.r_margin.right
   3736 	|| oldtw->text.r_margin.top != newtw->text.r_margin.top
   3737 	|| oldtw->text.sink != newtw->text.sink
   3738 	|| newtw->text.redisplay_needed) {
   3739 	if (oldtw->text.wrap != newtw->text.wrap) {
   3740 	    newtw->text.left_margin = newtw->text.margin.left =
   3741 		newtw->text.r_margin.left;
   3742 	    if (oldtw->text.lt.top == newtw->text.lt.top)
   3743 		newtw->text.lt.top = SrcScan(newtw->text.source, 0, XawstEOL,
   3744 					     XawsdLeft, 1, False);
   3745 	}
   3746 	newtw->text.showposition = True;
   3747 #ifndef OLDXAW
   3748 	show_lc = True;
   3749 	newtw->text.source_changed = SRC_CHANGE_OVERLAP;
   3750 #endif
   3751 	_XawTextBuildLineTable(newtw, newtw->text.lt.top, True);
   3752 	redisplay = True;
   3753     }
   3754 
   3755 #ifndef OLDXAW
   3756     if (newtw->text.left_column < 0)
   3757 	newtw->text.left_column = 0;
   3758     if (newtw->text.right_column < 0)
   3759 	newtw->text.right_column = 0;
   3760 #endif
   3761 
   3762     _XawTextExecuteUpdate(newtw);
   3763 
   3764 #ifndef OLDXAW
   3765     if (show_lc)
   3766 	_XawTextSetLineAndColumnNumber(newtw, True);
   3767 #endif
   3768 
   3769     if (redisplay)
   3770 	_XawTextSetScrollBars(newtw);
   3771 
   3772     return (redisplay);
   3773 }
   3774 
   3775 /* invoked by the Simple widget's SetValues */
   3776 static Bool
   3777 XawTextChangeSensitive(Widget w)
   3778 {
   3779     Arg args[1];
   3780     TextWidget tw = (TextWidget)w;
   3781 
   3782     (*(&simpleClassRec)->simple_class.change_sensitive)(w);
   3783 
   3784     XtSetArg(args[0], XtNancestorSensitive,
   3785 	     (tw->core.ancestor_sensitive && tw->core.sensitive));
   3786     if (tw->text.vbar)
   3787 	XtSetValues(tw->text.vbar, args, ONE);
   3788     if (tw->text.hbar)
   3789 	XtSetValues(tw->text.hbar, args, ONE);
   3790     return (False);
   3791 }
   3792 
   3793 /*
   3794  * Function:
   3795  *	XawTextGetValuesHook
   3796  *
   3797  * Parameters:
   3798  *	w	 - Text Widget
   3799  *	args	 - argument list
   3800  *	num_args - number of args
   3801  *
   3802  * Description:
   3803  *	  This is a get values hook routine that gets the
   3804  *		     values in the text source and sink.
   3805  */
   3806 static void
   3807 XawTextGetValuesHook(Widget w, ArgList args, Cardinal *num_args)
   3808 {
   3809     XtGetValues(((TextWidget)w)->text.source, args, *num_args);
   3810     XtGetValues(((TextWidget)w)->text.sink, args, *num_args);
   3811 }
   3812 
   3813 /*
   3814  * Function:
   3815  *	FindGoodPosition
   3816  *
   3817  * Parameters:
   3818  *	pos - any position
   3819  *
   3820  * Description:
   3821  *	Returns a valid position given any position.
   3822  *
   3823  * Returns:
   3824  *	A position between (0 and lastPos)
   3825  */
   3826 static XawTextPosition
   3827 FindGoodPosition(TextWidget ctx, XawTextPosition pos)
   3828 {
   3829     if (pos < 0)
   3830 	return (0);
   3831     return (((pos > ctx->text.lastPos) ? ctx->text.lastPos : pos));
   3832 }
   3833 
   3834 /* Li wrote this so the IM can find a given text position's screen position */
   3835 void
   3836 _XawTextPosToXY(Widget w, XawTextPosition pos, Position *x, Position *y)
   3837 {
   3838     int line, ix, iy;
   3839 
   3840     LineAndXYForPosition((TextWidget)w, pos, &line, &ix, &iy);
   3841     *x = (Position)ix;
   3842     *y = (Position)iy;
   3843 }
   3844 
   3845 /*******************************************************************
   3846 The following routines provide procedural interfaces to Text window state
   3847 setting and getting. They need to be redone so than the args code can use
   3848 them. I suggest we create a complete set that takes the context as an
   3849 argument and then have the public version lookup the context and call the
   3850 internal one. The major value of this set is that they have actual application
   3851 clients and therefore the functionality provided is required for any future
   3852 version of Text.
   3853 ********************************************************************/
   3854 void
   3855 XawTextDisplay(Widget w)
   3856 {
   3857     TextWidget ctx = (TextWidget)w;
   3858 
   3859     if (!XtIsRealized(w))
   3860 	return;
   3861 
   3862     _XawTextPrepareToUpdate(ctx);
   3863     ctx->text.clear_to_eol = True;
   3864     DisplayTextWindow(w);
   3865     _XawTextExecuteUpdate(ctx);
   3866 }
   3867 
   3868 void
   3869 XawTextSetSelectionArray(Widget w, XawTextSelectType *sarray)
   3870 {
   3871     ((TextWidget)w)->text.sarray = sarray;
   3872 }
   3873 
   3874 void
   3875 XawTextGetSelectionPos(Widget w, XawTextPosition *left, XawTextPosition *right)
   3876 {
   3877     *left = ((TextWidget)w)->text.s.left;
   3878     *right = ((TextWidget)w)->text.s.right;
   3879 }
   3880 
   3881 void
   3882 _XawTextSetSource(Widget w, Widget source,
   3883 		  XawTextPosition top, XawTextPosition startPos)
   3884 {
   3885     TextWidget ctx = (TextWidget)w;
   3886 #ifndef OLDXAW
   3887     Bool resolve = False;
   3888 #endif
   3889 
   3890 #ifndef OLDXAW
   3891     if (source != ctx->text.source)
   3892 	_XawSourceRemoveText(ctx->text.source, w, ctx->text.source &&
   3893 			     XtParent(ctx->text.source) == w);
   3894     _XawSourceAddText(source, w);
   3895 
   3896     if (source != ctx->text.source || ctx->text.insertPos != startPos)
   3897 	resolve = True;
   3898 
   3899     ctx->text.source_changed = SRC_CHANGE_OVERLAP;
   3900 #endif
   3901     ctx->text.source = source;
   3902     ctx->text.s.left = ctx->text.s.right = 0;
   3903     ctx->text.lastPos = GETLASTPOS;
   3904     top = FindGoodPosition(ctx, top);
   3905     startPos = FindGoodPosition(ctx, startPos);
   3906     ctx->text.insertPos = ctx->text.old_insert = startPos;
   3907     _XawTextPrepareToUpdate(ctx);
   3908 
   3909     _XawTextBuildLineTable(ctx, top, True);
   3910 
   3911     _XawTextExecuteUpdate(ctx);
   3912 #ifndef OLDXAW
   3913     if (resolve)
   3914 	_XawTextSetLineAndColumnNumber(ctx, True);
   3915 #endif
   3916 }
   3917 
   3918 void
   3919 XawTextSetSource(Widget w, Widget source, XawTextPosition top)
   3920 {
   3921     _XawTextSetSource(w, source, top, top);
   3922 }
   3923 
   3924 /*
   3925  * This public routine deletes the text from startPos to endPos in a source and
   3926  * then inserts, at startPos, the text that was passed. As a side effect it
   3927  * "invalidates" that portion of the displayed text (if any), so that things
   3928  * will be repainted properly.
   3929  */
   3930 int
   3931 XawTextReplace(Widget w, XawTextPosition startPos, XawTextPosition endPos,
   3932 	       XawTextBlock *text)
   3933 {
   3934     TextWidget ctx = (TextWidget)w;
   3935     int result;
   3936 #ifndef OLDXAW
   3937     Cardinal i;
   3938     TextSrcObject src = (TextSrcObject)ctx->text.source;
   3939 
   3940     for (i = 0; i < src->textSrc.num_text; i++)
   3941 	_XawTextPrepareToUpdate((TextWidget)src->textSrc.text[i]);
   3942 #else
   3943     _XawTextPrepareToUpdate(ctx);
   3944 #endif
   3945 
   3946     endPos = FindGoodPosition(ctx, endPos);
   3947     startPos = FindGoodPosition(ctx, startPos);
   3948     result = _XawTextReplace(ctx, startPos, endPos, text);
   3949 
   3950 #ifndef OLDXAW
   3951     for (i = 0; i < src->textSrc.num_text; i++)
   3952 	_XawTextExecuteUpdate((TextWidget)src->textSrc.text[i]);
   3953 #else
   3954     _XawTextExecuteUpdate(ctx);
   3955 #endif
   3956 
   3957     return (result);
   3958 }
   3959 
   3960 XawTextPosition
   3961 XawTextTopPosition(Widget w)
   3962 {
   3963     return (((TextWidget)w)->text.lt.top);
   3964 }
   3965 
   3966 XawTextPosition
   3967 XawTextLastPosition(Widget w)
   3968 {
   3969     return (((TextWidget)w)->text.lastPos);
   3970 }
   3971 
   3972 void
   3973 XawTextSetInsertionPoint(Widget w, XawTextPosition position)
   3974 {
   3975     TextWidget ctx = (TextWidget)w;
   3976 
   3977     _XawTextPrepareToUpdate(ctx);
   3978     ctx->text.insertPos = FindGoodPosition(ctx, position);
   3979     ctx->text.showposition = True;
   3980     ctx->text.from_left = -1;
   3981 
   3982     _XawTextExecuteUpdate(ctx);
   3983 #ifndef OLDXAW
   3984     _XawTextSetLineAndColumnNumber(ctx, False);
   3985 #endif
   3986 }
   3987 
   3988 XawTextPosition
   3989 XawTextGetInsertionPoint(Widget w)
   3990 {
   3991     return (((TextWidget)w)->text.insertPos);
   3992 }
   3993 
   3994 /*
   3995  * Note: Must walk the selection list in opposite order from TextLoseSelection
   3996  */
   3997 void
   3998 XawTextUnsetSelection(Widget w)
   3999 {
   4000     TextWidget ctx = (TextWidget)w;
   4001 
   4002     while (ctx->text.s.atom_count != 0) {
   4003 	Atom sel = ctx->text.s.selections[ctx->text.s.atom_count - 1];
   4004 
   4005 	if (sel != (Atom) 0) {
   4006 	    /*
   4007 	     * As selections are lost the atom_count will decrement
   4008 	     */
   4009 	    if (GetCutBufferNumber(sel) == NOT_A_CUT_BUFFER)
   4010 		XtDisownSelection(w, sel, ctx->text.time);
   4011 	    TextLoseSelection(w, &sel); /* In case this is a cut buffer, or
   4012 					   XtDisownSelection failed to call us */
   4013 	}
   4014     }
   4015 }
   4016 
   4017 void
   4018 XawTextSetSelection(Widget w, XawTextPosition left, XawTextPosition right)
   4019 {
   4020     TextWidget ctx = (TextWidget)w;
   4021 
   4022     _XawTextPrepareToUpdate(ctx);
   4023     _XawTextSetSelection(ctx, FindGoodPosition(ctx, left),
   4024 			 FindGoodPosition(ctx, right), NULL, 0);
   4025     _XawTextExecuteUpdate(ctx);
   4026 }
   4027 
   4028 void
   4029 XawTextInvalidate(Widget w, XawTextPosition from, XawTextPosition to)
   4030 {
   4031     TextWidget ctx = (TextWidget)w;
   4032 
   4033     from = FindGoodPosition(ctx, from);
   4034     to = FindGoodPosition(ctx, to);
   4035     ctx->text.lastPos = GETLASTPOS;
   4036     _XawTextPrepareToUpdate(ctx);
   4037     _XawTextNeedsUpdating(ctx, from, to);
   4038     _XawTextExecuteUpdate(ctx);
   4039 }
   4040 
   4041 /*ARGSUSED*/
   4042 void
   4043 XawTextDisableRedisplay(Widget w)
   4044 {
   4045     ((TextWidget)w)->text.update_disabled = True;
   4046     _XawTextPrepareToUpdate((TextWidget)w);
   4047 }
   4048 
   4049 void
   4050 XawTextEnableRedisplay(Widget w)
   4051 {
   4052     TextWidget ctx = (TextWidget)w;
   4053     XawTextPosition lastPos;
   4054 
   4055     if (!ctx->text.update_disabled)
   4056 	return;
   4057 
   4058     ctx->text.update_disabled = False;
   4059     lastPos = ctx->text.lastPos = GETLASTPOS;
   4060     ctx->text.lt.top = FindGoodPosition(ctx, ctx->text.lt.top);
   4061     ctx->text.insertPos = FindGoodPosition(ctx, ctx->text.insertPos);
   4062 
   4063     if (ctx->text.s.left > lastPos || ctx->text.s.right > lastPos)
   4064 	ctx->text.s.left = ctx->text.s.right = 0;
   4065 
   4066     _XawTextExecuteUpdate(ctx);
   4067 }
   4068 
   4069 Widget
   4070 XawTextGetSource(Widget w)
   4071 {
   4072     return (((TextWidget)w)->text.source);
   4073 }
   4074 
   4075 Widget
   4076 XawTextGetSink(Widget w)
   4077 {
   4078     return (((TextWidget)w)->text.sink);
   4079 }
   4080 
   4081 void
   4082 XawTextDisplayCaret(Widget w,
   4083 #if NeedWidePrototypes
   4084 	int display_caret
   4085 #else
   4086 	Boolean display_caret
   4087 #endif
   4088 )
   4089 {
   4090     TextWidget ctx = (TextWidget)w;
   4091 
   4092     if (XtIsRealized(w)) {
   4093 	_XawTextPrepareToUpdate(ctx);
   4094 	ctx->text.display_caret = display_caret;
   4095 	_XawTextExecuteUpdate(ctx);
   4096     }
   4097     else
   4098 	ctx->text.display_caret = display_caret;
   4099 }
   4100 
   4101 /*
   4102  * Function:
   4103  *	XawTextSearch
   4104  *
   4105  * Parameters:
   4106  *	w    - text widget
   4107  *	dir  - direction to search
   4108  *	text - text block containing info about the string to search for
   4109  *
   4110  * Description:
   4111  *	Searches for the given text block.
   4112  *
   4113  * Returns:
   4114  *	The position of the text found, or XawTextSearchError on an error
   4115  */
   4116 XawTextPosition
   4117 XawTextSearch(Widget w,
   4118 #if NeedWidePrototypes
   4119 	int dir,
   4120 #else
   4121 	XawTextScanDirection dir,
   4122 #endif
   4123 	XawTextBlock *text)
   4124 {
   4125     TextWidget ctx = (TextWidget)w;
   4126 
   4127     return (SrcSearch(ctx->text.source, ctx->text.insertPos, dir, text));
   4128 }
   4129 
   4130 TextClassRec textClassRec = {
   4131   /* core */
   4132   {
   4133     (WidgetClass)&simpleClassRec,	/* superclass */
   4134     "Text",				/* class_name */
   4135     sizeof(TextRec),			/* widget_size */
   4136     XawTextClassInitialize,		/* class_initialize */
   4137     NULL,				/* class_part_init */
   4138     False,				/* class_inited */
   4139     XawTextInitialize,			/* initialize */
   4140     NULL,				/* initialize_hook */
   4141     XawTextRealize,			/* realize */
   4142     _XawTextActionsTable,		/* actions */
   4143     0,					/* num_actions */
   4144     resources,				/* resources */
   4145     XtNumber(resources),		/* num_resource */
   4146     NULLQUARK,				/* xrm_class */
   4147     True,				/* compress_motion */
   4148     XtExposeGraphicsExpose |		/* compress_exposure */
   4149 	XtExposeNoExpose,
   4150     True,				/* compress_enterleave */
   4151     False,				/* visible_interest */
   4152     XawTextDestroy,			/* destroy */
   4153     XawTextResize,			/* resize */
   4154     XawTextExpose,			/* expose */
   4155     XawTextSetValues,			/* set_values */
   4156     NULL,				/* set_values_hook */
   4157     XtInheritSetValuesAlmost,		/* set_values_almost */
   4158     XawTextGetValuesHook,		/* get_values_hook */
   4159     NULL,				/* accept_focus */
   4160     XtVersion,				/* version */
   4161     NULL,				/* callback_private */
   4162     _XawDefaultTextTranslations,	/* tm_table */
   4163     XtInheritQueryGeometry,		/* query_geometry */
   4164     XtInheritDisplayAccelerator,	/* display_accelerator */
   4165     NULL,				/* extension */
   4166   },
   4167   /* simple */
   4168   {
   4169     XawTextChangeSensitive,		/* change_sensitive */
   4170 #ifndef OLDXAW
   4171     NULL,
   4172 #endif
   4173   },
   4174   /* text */
   4175   {
   4176     NULL,				/* extension */
   4177   }
   4178 };
   4179 
   4180 WidgetClass textWidgetClass = (WidgetClass)&textClassRec;
   4181