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