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