1/***********************************************************
2
3Copyright 1987, 1988, 1994, 1998  The Open Group
4
5Permission to use, copy, modify, distribute, and sell this software and its
6documentation for any purpose is hereby granted without fee, provided that
7the above copyright notice appear in all copies and that both that
8copyright notice and this permission notice appear in supporting
9documentation.
10
11The above copyright notice and this permission notice shall be included in
12all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
21Except as contained in this notice, the name of The Open Group shall not be
22used in advertising or otherwise to promote the sale, use or other dealings
23in this Software without prior written authorization from The Open Group.
24
25
26Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
27
28                        All Rights Reserved
29
30Permission to use, copy, modify, and distribute this software and its
31documentation for any purpose and without fee is hereby granted,
32provided that the above copyright notice appear in all copies and that
33both that copyright notice and this permission notice appear in
34supporting documentation, and that the name of Digital not be
35used in advertising or publicity pertaining to distribution of the
36software without specific, written prior permission.
37
38DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
39ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
40DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
41ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
42WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
43ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
44SOFTWARE.
45
46******************************************************************/
47
48#ifdef HAVE_CONFIG_H
49#include <config.h>
50#endif
51#include <stdio.h>
52#include <stdlib.h>
53#include <X11/IntrinsicP.h>
54#include <X11/StringDefs.h>
55#include <X11/Xatom.h>
56#include <X11/Xaw/XawInit.h>
57#include <X11/Xaw/AsciiSinkP.h>
58#include <X11/Xaw/AsciiSrcP.h>
59#include <X11/Xaw/TextP.h>
60#include "Private.h"
61
62#ifdef GETLASTPOS
63#undef GETLASTPOS		/* We will use our own GETLASTPOS */
64#endif
65
66#define GETLASTPOS	\
67	XawTextSourceScan(source, 0, XawstAll, XawsdRight, 1, True)
68
69/*
70 * Class Methods
71 */
72static void XawAsciiSinkClassPartInitialize(WidgetClass);
73static void XawAsciiSinkInitialize(Widget, Widget, ArgList, Cardinal*);
74static void XawAsciiSinkDestroy(Widget);
75static void XawAsciiSinkResize(Widget);
76static Boolean XawAsciiSinkSetValues(Widget, Widget, Widget,
77				     ArgList, Cardinal*);
78static int MaxLines(Widget, unsigned int);
79static int MaxHeight(Widget, int);
80static void SetTabs(Widget, int, short*);
81static void DisplayText(Widget, int, int,
82			XawTextPosition, XawTextPosition, Bool);
83static void InsertCursor(Widget, int, int, XawTextInsertState);
84static void FindPosition(Widget, XawTextPosition, int, int, Bool,
85			 XawTextPosition*, int*, int*);
86static void FindDistance(Widget, XawTextPosition, int, XawTextPosition, int*,
87			 XawTextPosition*, int*);
88static void Resolve(Widget, XawTextPosition, int, int, XawTextPosition*);
89static void GetCursorBounds(Widget, XRectangle*);
90#ifndef OLDXAW
91static void AsciiPreparePaint(Widget, int, int,
92			      XawTextPosition, XawTextPosition, Bool);
93static void AsciiDoPaint(Widget);
94#endif
95
96/*
97 * Prototypes
98 */
99static void GetGC(AsciiSinkObject);
100static int CharWidth(AsciiSinkObject, XFontStruct*, int, unsigned int);
101static unsigned int PaintText(Widget w, GC gc, int x, int y,
102			      char *buf, int len, Bool);
103
104/*
105 * Defined in TextSink.c
106 */
107void _XawTextSinkClearToBackground(Widget, int, int, unsigned, unsigned);
108
109/*
110 * Initialization
111 */
112#define offset(field) XtOffsetOf(AsciiSinkRec, ascii_sink.field)
113static XtResource resources[] = {
114  {
115    XtNfont,
116    XtCFont,
117    XtRFontStruct,
118    sizeof(XFontStruct*),
119    offset(font),
120    XtRString,
121    (XtPointer)XtDefaultFont
122  },
123  {
124    XtNecho,
125    XtCOutput,
126    XtRBoolean,
127    sizeof(Boolean),
128    offset(echo),
129    XtRImmediate,
130    (XtPointer)True
131  },
132  {
133    XtNdisplayNonprinting,
134    XtCOutput,
135    XtRBoolean,
136    sizeof(Boolean),
137    offset(display_nonprinting),
138    XtRImmediate,
139    (XtPointer)
140    True
141  },
142};
143#undef offset
144
145#define Superclass	(&textSinkClassRec)
146AsciiSinkClassRec asciiSinkClassRec = {
147  /* object */
148  {
149    (WidgetClass)Superclass,	/* superclass */
150    "AsciiSink",		/* class_name */
151    sizeof(AsciiSinkRec),	/* widget_size */
152    XawInitializeWidgetSet,	/* class_initialize */
153    XawAsciiSinkClassPartInitialize,	/* class_part_initialize */
154    False,			/* class_inited	*/
155    XawAsciiSinkInitialize,	/* initialize */
156    NULL,			/* initialize_hook */
157    NULL,			/* obj1 */
158    NULL,			/* obj2 */
159    0,				/* obj3 */
160    resources,			/* resources */
161    XtNumber(resources),	/* num_resources */
162    NULLQUARK,			/* xrm_class */
163    False,			/* obj4 */
164    False,			/* obj5 */
165    False,			/* obj6 */
166    False,			/* obj7 */
167    XawAsciiSinkDestroy,	/* destroy */
168    (XtProc)XawAsciiSinkResize,	/* obj8 */
169    NULL,			/* obj9 */
170    XawAsciiSinkSetValues,	/* set_values */
171    NULL,			/* set_values_hook */
172    NULL,			/* obj10 */
173    NULL,			/* get_values_hook */
174    NULL,			/* obj11 */
175    XtVersion,			/* version */
176    NULL,			/* callback_private */
177    NULL,			/* obj12 */
178    NULL,			/* obj13 */
179    NULL,			/* obj14 */
180    NULL,			/* extension */
181  },
182  /* text_sink */
183  {
184    DisplayText,		/* DisplayText */
185    InsertCursor,		/* InsertCursor */
186    XtInheritClearToBackground,	/* ClearToBackground */
187    FindPosition,		/* FindPosition */
188    FindDistance,		/* FindDistance */
189    Resolve,			/* Resolve */
190    MaxLines,			/* MaxLines */
191    MaxHeight,			/* MaxHeight */
192    SetTabs,			/* SetTabs */
193    GetCursorBounds,		/* GetCursorBounds */
194#ifndef OLDXAW
195    NULL			/* extension */
196#endif
197  },
198  /* ascii_sink */
199  {
200    NULL,			/* extension */
201  }
202};
203
204WidgetClass asciiSinkObjectClass = (WidgetClass)&asciiSinkClassRec;
205
206/*
207 * Implementation
208 */
209static void
210XawAsciiSinkClassPartInitialize(WidgetClass wc _X_UNUSED)
211{
212#ifndef OLDXAW
213    AsciiSinkObjectClass cclass = (AsciiSinkObjectClass)wc;
214    XrmQuark record_type = XrmPermStringToQuark("TextSink");
215    TextSinkExt ext = cclass->text_sink_class.extension;
216
217    while (ext) {
218	if (ext->record_type == record_type &&
219	    ext->version == 1) {
220	    ext->PreparePaint = AsciiPreparePaint;
221	    ext->DoPaint = AsciiDoPaint;
222	    break;
223	}
224	ext = (TextSinkExt)ext->next_extension;
225    }
226    if (ext == NULL)
227	XtError("TextSinkClass: cannot resolve extension.\n");
228#endif
229}
230
231static int
232CharWidth(AsciiSinkObject sink, XFontStruct *font, int x, unsigned int c)
233{
234    int width = 0;
235
236    if (c == XawLF)
237	return (0);
238
239    if (c == XawTAB) {
240	int i;
241	Position *tab;
242
243	width = x;
244	/* Adjust for Left Margin */
245	x -= ((TextWidget)XtParent((Widget)sink))->text.left_margin;
246
247	i = 0;
248	tab = sink->text_sink.tabs;
249	/*CONSTCOND*/
250	while (1) {
251	    if (x >= 0 && x < *tab)
252		return (*tab - x);
253	    /* Start again */
254	    if (++i >= sink->text_sink.tab_count) {
255		x -= *tab;
256		i = 0;
257		tab = sink->text_sink.tabs;
258		if (width == x)
259		    return (0);
260	    }
261	    else
262		++tab;
263	}
264	/*NOTREACHED*/
265    }
266
267    if ((c & 0177) < XawSP || c == 0177) {
268	if (sink->ascii_sink.display_nonprinting) {
269	    if (c > 0177) {
270		width = CharWidth(sink, font, x, '\\');
271		width += CharWidth(sink, font, x, ((c >> 6) & 7) + '0');
272		width += CharWidth(sink, font, x, ((c >> 3) & 7) + '0');
273		c = (c & 7) + '0';
274	    }
275	    else {
276		width = CharWidth(sink, font, x, '^');
277		if ((c |= 0100) == 0177)
278		    c = '?';
279	    }
280	}
281	else
282	    c = XawSP;
283    }
284
285    if (font->per_char
286	&& (c >= font->min_char_or_byte2 && c <= font->max_char_or_byte2))
287	width += font->per_char[c - font->min_char_or_byte2].width;
288    else
289	width += font->min_bounds.width;
290
291    return (width);
292}
293
294#ifndef OLDXAW
295static int
296GetTextWidth(TextWidget ctx, int current_width, XFontStruct *font,
297	     XawTextPosition from, int length)
298{
299    int width = 0;
300
301    while (length > 0) {
302	int i;
303	XawTextBlock block;
304	XawTextPosition pos = XawTextSourceRead(ctx->text.source, from, &block, length);
305
306	length = (int)(length - (pos - from));
307	from = pos;
308	for (i = 0; i < block.length; i++)
309	    width += CharWidth((AsciiSinkObject)ctx->text.sink, font,
310			       current_width + width,
311			       (unsigned char)block.ptr[i]);
312    }
313
314    return (width);
315}
316
317static
318void CalculateBearing(TextWidget ctx, XawTextPosition position, int x, int y,
319		      int ascent, int descent, Bool highlight, Bool right)
320{
321/*
322 * Sample case:
323 *
324 * lbearing|    width	 |rbearing
325 *	   |		 |
326 *	   |	       ####
327 *	   |	     ### |
328 *	   |	   ####  |
329 *	   |	  ####	 |
330 *	   |  ########## |
331 *	   |	####	 |
332 *	   |   ####	 |
333 *	   |  ####	 |
334 *	   | ####	 |
335 *	   |###		 |
336 *	 ####		 |
337 *	   |		 |
338 *
339 */
340    AsciiSinkObject sink = (AsciiSinkObject)ctx->text.sink;
341    XawTextAnchor *anchor;
342    XawTextEntity *entity;
343    XawTextProperty *property;
344    XawTextBlock block;
345    XFontStruct *font;
346
347    property = NULL;
348    if (XawTextSourceAnchorAndEntity(ctx->text.source, position,
349				     &anchor, &entity) &&
350	(property = XawTextSinkGetProperty((Widget)sink,
351					   entity->property)) != NULL &&
352	(property->mask & XAW_TPROP_FONT))
353	font = property->font;
354    else
355	font = sink->ascii_sink.font;
356    if (right) {
357	if (font->max_bounds.rbearing > 0) {
358	    int rbearing = font->max_bounds.rbearing - font->max_bounds.width;
359	    unsigned char c;
360
361	    (void)XawTextSourceRead(ctx->text.source, position, &block, 1);
362	    c = *(unsigned char*)block.ptr;
363	    if (c == '\t' || c == '\n')
364		c = ' ';
365	    else if ((c & 0177) < XawSP || c == 0177) {
366		if (sink->ascii_sink.display_nonprinting)
367		    c = (unsigned char)(c > 0177 ? (c & 7) + '0' : c + '@');
368		else
369		    c = ' ';
370	    }
371	    if (font->per_char &&
372		(c >= font->min_char_or_byte2 && c <= font->max_char_or_byte2))
373		rbearing = font->per_char[c - font->min_char_or_byte2].rbearing -
374			   font->per_char[c - font->min_char_or_byte2].width;
375	    if (rbearing > 0) {
376		XawTextPaintStruct *paint = XtNew(XawTextPaintStruct);
377		paint->next = sink->text_sink.paint->bearings;
378		sink->text_sink.paint->bearings = paint;
379		paint->x = x - (paint->width = CharWidth(sink, font, 0, c));
380		paint->y = y + ascent;
381		paint->property = property;
382		paint->max_ascent = ascent;
383		paint->max_descent = descent;
384		paint->backtabs = NULL;
385		paint->highlight = (Boolean)highlight;
386		paint->length = 1;
387		paint->text = XtMalloc(1);
388		paint->text[0] = (char)c;
389	    }
390	}
391    }
392    else {
393	if (font->min_bounds.lbearing < 0) {
394	    int lbearing = font->min_bounds.lbearing;
395	    unsigned char c;
396
397	    (void)XawTextSourceRead(ctx->text.source, position, &block, 1);
398	    c = *(unsigned char*)block.ptr;
399	    if (c == '\t' || c == '\n')
400		c = ' ';
401	    else if ((c & 0177) < XawSP || c == 0177) {
402		if (sink->ascii_sink.display_nonprinting)
403		    c = (unsigned char)(c > 0177 ? '\\' : c + '^');
404		else
405		    c = ' ';
406	    }
407	    if (font->per_char &&
408		(c >= font->min_char_or_byte2 && c <= font->max_char_or_byte2))
409		lbearing = font->per_char[c - font->min_char_or_byte2].lbearing;
410	    if (lbearing < 0) {
411		XawTextPaintStruct *paint = XtNew(XawTextPaintStruct);
412		paint->next = sink->text_sink.paint->bearings;
413		sink->text_sink.paint->bearings = paint;
414		paint->x = x;
415		paint->width = -CharWidth(sink, font, 0, c);
416		paint->y = y + ascent;
417		paint->property = property;
418		paint->max_ascent = ascent;
419		paint->max_descent = descent;
420		paint->backtabs = NULL;
421		paint->highlight = (Boolean)highlight;
422		paint->length = 1;
423		paint->text = XtMalloc(1);
424		paint->text[0] = (char)c;
425	    }
426	}
427    }
428}
429
430static void
431AsciiPreparePaint(Widget w, int y, int line,
432		  XawTextPosition from, XawTextPosition to, Bool highlight)
433{
434    static XmuSegment segment;
435    static XmuScanline next;
436    static XmuScanline scanline = {0, &segment, &next};
437    static XmuArea area = {&scanline};
438
439    TextWidget ctx = (TextWidget)XtParent(w);
440    AsciiSinkObject sink = (AsciiSinkObject)ctx->text.sink;
441    XawTextPosition left, right, pos, tmp, length;
442    XawTextAnchor *anchor;
443    XawTextEntity *entity;
444    XawTextProperty *property;
445    int i, ascent = 0, descent = 0, xl, xr, x = ctx->text.left_margin;
446    XawTextBlock block;
447    XFontStruct *font;
448
449    if (!sink->ascii_sink.echo)
450	return;
451
452    /* pass 1: calculate ascent/descent values and x coordinate */
453    /* XXX the MAX ascent/descent value should be in the line table XXX */
454    /* XXX the x coordinate can be a parameter, but since it is required
455	   to calculate the ascent/descent, do it here to avoid an extra
456	   search in the entities */
457    pos = left = ctx->text.lt.info[line].position;
458    right = ctx->text.lt.info[line + 1].position;
459    right = XawMin(right, ctx->text.lastPos + 1);
460    while (pos < right) {
461	if (XawTextSourceAnchorAndEntity(ctx->text.source, pos,
462					 &anchor, &entity)) {
463	    if ((property = XawTextSinkGetProperty((Widget)sink,
464						   entity->property)) != NULL &&
465		(property->mask & XAW_TPROP_FONT))
466		font = property->font;
467	    else
468		font = sink->ascii_sink.font;
469	    tmp = pos;
470	    pos = anchor->position + entity->offset + entity->length;
471	    if ((length = XawMin(from, pos) - tmp) > 0)
472		x += GetTextWidth(ctx, x, font, tmp, (int)length);
473	    ascent = XawMax(font->ascent, ascent);
474	    descent = XawMax(font->descent, descent);
475	}
476	else if (anchor) {
477	    ascent = XawMax(sink->ascii_sink.font->ascent, ascent);
478	    descent = XawMax(sink->ascii_sink.font->descent, descent);
479	    while (entity && pos < right) {
480		tmp = pos;
481		if ((pos = anchor->position + entity->offset) < tmp)
482		    pos = tmp;
483		else {
484		    if ((length = XawMin(from, pos) - tmp) > 0) {
485			x += GetTextWidth(ctx, x, sink->ascii_sink.font, tmp,
486					  (int)length);
487			tmp += length;
488		    }
489		    if (pos < right) {
490			pos += entity->length;
491			if ((property = XawTextSinkGetProperty((Widget)sink,
492							       entity->property)) != NULL &&
493			    (property->mask & XAW_TPROP_FONT))
494			    font = property->font;
495			else
496			    font = sink->ascii_sink.font;
497			if ((length = XawMin(from, pos) - tmp) > 0)
498			    x += GetTextWidth(ctx, x, font, tmp, (int)length);
499			ascent = XawMax(font->ascent, ascent);
500			descent = XawMax(font->descent, descent);
501		    }
502		}
503		entity = entity->next;
504	    }
505
506	    if (anchor->entities == NULL) {
507		tmp = XawMin(pos, from);
508		if ((length = from - tmp) > 0)
509		    x += GetTextWidth(ctx, x, sink->ascii_sink.font, tmp, (int)length);
510		break;
511	    }
512	}
513	else {
514	    tmp = XawMin(pos, from);
515	    if ((length = from - tmp) > 0)
516		x += GetTextWidth(ctx, x, sink->ascii_sink.font, tmp, (int)length);
517	    ascent = XawMax(sink->ascii_sink.font->ascent, ascent);
518	    descent = XawMax(sink->ascii_sink.font->descent, descent);
519	    break;
520	}
521    }
522    if (!ascent)
523	ascent = sink->ascii_sink.font->ascent;
524    if (!descent)
525	descent = sink->ascii_sink.font->descent;
526
527    xl = x;
528
529    /* pass 2: feed the XawTextPaintStruct lists */
530    pos = from;
531    while (pos < to) {
532	int bufsiz;
533	XawTextPaintStruct *paint = XtNew(XawTextPaintStruct);
534
535	paint->next = sink->text_sink.paint->paint;
536	sink->text_sink.paint->paint = paint;
537	paint->x = x;
538	paint->y = y + ascent;
539	paint->property = NULL;
540	paint->max_ascent = ascent;
541	paint->max_descent = descent;
542	paint->backtabs = NULL;
543	paint->highlight = (Boolean)highlight;
544
545	tmp = pos;
546	if (XawTextSourceAnchorAndEntity(ctx->text.source, pos,
547					 &anchor, &entity)) {
548	    pos = anchor->position + entity->offset + entity->length;
549	    if ((paint->property = XawTextSinkGetProperty((Widget)sink,
550						   entity->property)) != NULL &&
551		(paint->property->mask & XAW_TPROP_FONT))
552		font = paint->property->font;
553	    else
554		font = sink->ascii_sink.font;
555	}
556	else {
557	    if (anchor) {
558		while (entity && anchor->position + entity->offset < pos)
559		    entity = entity->next;
560		if (entity)
561		    pos = anchor->position + entity->offset;
562		else
563		    pos = to;
564	    }
565	    else
566		pos = to;
567	    font = sink->ascii_sink.font;
568	}
569	pos = XawMin(pos, to);
570	length = pos - tmp;
571
572	paint->text = XtMalloc((Cardinal)(bufsiz = (int)(pos - tmp + 4)));
573	paint->length = 0;
574	segment.x1 = x;
575
576	while (length > 0) {
577	    XawTextPosition pos2 = XawTextSourceRead(ctx->text.source, tmp, &block, (int)length);
578	    length = pos - pos2;
579	    tmp = pos2;
580	    for (i = 0; i < block.length; i++) {
581		unsigned char c = (unsigned char)block.ptr[i];
582
583		if ((paint->length + 4) > (unsigned)bufsiz)
584		    paint->text = XtRealloc(paint->text, (Cardinal)(bufsiz += 32));
585		paint->text[paint->length] = (char)c;
586		if (c == '\n') {
587		    x += CharWidth(sink, font, 0, ' ');
588		    continue;
589		}
590		if (c == '\t') {
591		    x += XTextWidth(font, paint->text, (int)paint->length);
592		    segment.x2 = x + CharWidth(sink, font, x, '\t');
593
594		    if (XmuValidSegment(&segment)) {
595			if (!highlight && (paint->property &&
596			    (paint->property->mask & XAW_TPROP_BACKGROUND))) {
597			    if (ascent > font->ascent) {
598				scanline.y = y;
599				next.y = y + ascent - font->ascent;
600				XmuAreaOr(sink->text_sink.paint->clip, &area);
601			    }
602			    if (descent >= font->descent) {
603				scanline.y = y + ascent + font->descent;
604				next.y = scanline.y + descent - font->descent + 1;
605				XmuAreaOr(sink->text_sink.paint->clip, &area);
606			    }
607			    if (paint->backtabs == NULL)
608				paint->backtabs = XmuCreateArea();
609			    scanline.y = y + ascent - font->ascent;
610			    next.y = y + ascent + font->descent;
611			    XmuAreaOr(paint->backtabs, &area);
612			}
613			else {
614			    scanline.y = y;
615			    next.y = ctx->text.lt.info[line + 1].y;
616			    if (highlight) {
617				if (!sink->text_sink.paint->hightabs)
618				    sink->text_sink.paint->hightabs =
619					XmuCreateArea();
620				XmuAreaOr(sink->text_sink.paint->hightabs, &area);
621			    }
622			    else
623				XmuAreaOr(sink->text_sink.paint->clip, &area);
624			}
625		    }
626
627		    paint->width = segment.x2 - segment.x1;
628		    x = segment.x1 = segment.x2;
629
630		    if (paint->length == 0) {
631			paint->x = x;
632			continue;
633		    }
634		    paint->text = XtRealloc(paint->text, paint->length);
635		    property = paint->property;
636		    paint = XtNew(XawTextPaintStruct);
637		    paint->next = sink->text_sink.paint->paint;
638		    sink->text_sink.paint->paint = paint;
639		    paint->x = x;
640		    paint->y = y + ascent;
641		    paint->property = property;
642		    paint->max_ascent = ascent;
643		    paint->max_descent = descent;
644		    paint->backtabs = NULL;
645		    paint->highlight = (Boolean)highlight;
646		    paint->text = XtMalloc((Cardinal)(bufsiz = (int)(pos - tmp - length +
647						    block.length - i + 4)));
648		    paint->length = 0;
649		    continue;
650		}
651		if ((c & 0177) < XawSP || c == 0177) {
652		    if (sink->ascii_sink.display_nonprinting) {
653			if (c > 0177) {
654			    paint->text[paint->length++] = '\\';
655			    paint->text[paint->length++] = (char)(((c >> 6) & 7) + '0');
656			    paint->text[paint->length++] = (char)(((c >> 3) & 7) + '0');
657			    paint->text[paint->length] = (char)((c & 7) + '0');
658			}
659			else {
660			    c |= 0100;
661			    paint->text[paint->length++] = '^';
662			    paint->text[paint->length] = (char)(c == 0177 ? '?' : c);
663			}
664		    }
665		    else
666			paint->text[paint->length] = ' ';
667		}
668		paint->length++;
669	    }
670	}
671
672	x += XTextWidth(font, paint->text, (int)paint->length);
673	segment.x2 = x;
674	if (XmuValidSegment(&segment)) {
675	    /* erase only what really is needed */
676	    /*if (!highlight || (paint->property &&
677		(paint->property->mask & XAW_TPROP_BACKGROUND))) {
678		if (ascent > font->ascent) {
679		    scanline.y = y;
680		    next.y = y + ascent - font->ascent;
681		    XmuAreaOr(sink->text_sink.paint->clip, &area);
682		}
683		if (descent > font->descent) {
684		    scanline.y = y + ascent + font->descent;
685		    next.y = scanline.y + descent - font->descent;
686		    XmuAreaOr(sink->text_sink.paint->clip, &area);
687		}
688	    }
689	    else*/ {
690		scanline.y = y;
691		next.y = ctx->text.lt.info[line + 1].y;
692		XmuAreaOr(sink->text_sink.paint->clip, &area);
693	    }
694	}
695
696	paint->width = x - segment.x1;
697    }
698
699    xr = x;
700
701    /* pass 3: bearing clipping */
702    if (left < from) {
703	CalculateBearing(ctx, from - 1, xl, y, ascent, descent, highlight, True);
704	if (ctx->text.s.left < ctx->text.s.right) {
705	    if (ctx->text.s.right == from)
706		CalculateBearing(ctx, from, xl, y, ascent, descent, True, False);
707	    else if (ctx->text.s.left == from)
708		CalculateBearing(ctx, from, xl, y, ascent, descent, False, False);
709	}
710    }
711    right = XawMin(right, ctx->text.lastPos);
712    if (right >= to && to > from) {
713	if (to < right)
714	    CalculateBearing(ctx, to, xr, y, ascent, descent, highlight, False);
715	if (ctx->text.s.left < ctx->text.s.right) {
716	    if (ctx->text.s.right == to)
717		CalculateBearing(ctx, to - 1, xr, y, ascent, descent, False, True);
718	    else if (ctx->text.s.left == to)
719		CalculateBearing(ctx, to - 1, xr, y, ascent, descent, True, True);
720	}
721    }
722}
723
724static int
725qcmp_paint_struct(_Xconst void *left, _Xconst void *right)
726{
727    return (int)((*(XawTextPaintStruct* _Xconst *)left)->property -
728	         (*(XawTextPaintStruct* _Xconst *)right)->property);
729}
730
731static void
732AsciiDoPaint(Widget w)
733{
734    TextWidget ctx = (TextWidget)XtParent(w);
735    AsciiSinkObject sink = (AsciiSinkObject)ctx->text.sink;
736    XmuScanline *scan;
737    XmuSegment *seg;
738    XawTextPaintList *list = sink->text_sink.paint;
739    XawTextPaintStruct *paint = list->paint;
740    XawTextProperty *property;
741    XFontStruct *font = NULL;
742    XRectangle *rects;
743    int n_rects, i_rects;
744    GC gc;
745    Bool highlight;
746    XRectangle rect;
747    int width, height, line_width = -1;
748    XGCValues values;
749
750    /* pass 1: clear clipping areas */
751    /* XXX Don't use XDrawImageString because the font may be italic, and
752	   will get incorrectly drawn. Probably, it could be a good idea to
753	   check if this is the case, and do special processing. But this
754	   will need to be checked if required. */
755    for (scan = list->clip->scanline; scan && scan->next; scan = scan->next)
756	for (seg = scan->segment; seg; seg = seg->next)
757	    _XawTextSinkClearToBackground(ctx->text.sink,
758					  seg->x1, scan->y,
759					  (unsigned)(seg->x2 - seg->x1),
760					  (unsigned)(scan->next->y - scan->y));
761
762    if (paint && paint->next) {
763	XawTextPaintStruct **paints;
764	int i = 0, n_paints = 0;
765
766	while (paint) {
767	    paint = paint->next;
768	    ++n_paints;
769	}
770	paints = (XawTextPaintStruct**)
771	    XtMalloc((Cardinal)((size_t)n_paints * sizeof(XawTextPaintStruct)));
772	paint = list->paint;
773	while (paint) {
774	    paints[i++] = paint;
775	    paint = paint->next;
776	}
777	qsort((void*)paints, (size_t)n_paints, sizeof(XawTextPaintStruct*),
778	      qcmp_paint_struct);
779	list->paint = paints[0];
780	for (i = 0; i < n_paints - 1; i++)
781	    paints[i]->next = paints[i + 1];
782	paints[i]->next = NULL;
783	XtFree((XtPointer)paints);
784    }
785
786    /* pass 3: clip gc */
787    gc = sink->ascii_sink.normgc;
788
789    rect.x = ctx->text.r_margin.left;
790    rect.y = ctx->text.r_margin.top;
791    width = (int)XtWidth(ctx) - RHMargins(ctx);
792    height = (int)XtHeight(ctx) - RVMargins(ctx);
793    rect.width = (unsigned short)width;
794    rect.height = (unsigned short)height;
795    if (width >= 0 && height >= 0)
796	XSetClipRectangles(XtDisplay((Widget)ctx), gc,
797			   0, 0, &rect, 1, Unsorted);
798    else
799	XSetClipMask(XtDisplay((Widget)ctx), gc, None);
800
801    /* pass 4: draw backgrounds */
802    paint = list->paint;
803    property = NULL;
804    rects = NULL;
805    i_rects = n_rects = 0;
806    while (paint) {
807	if (paint->property && (paint->property->mask & XAW_TPROP_BACKGROUND)) {
808	    if (property != paint->property) {
809		if (i_rects)
810		    XFillRectangles(XtDisplay(ctx), XtWindow(ctx), gc,
811				    rects, i_rects);
812		i_rects = 0;
813		property = paint->property;
814		if (property->mask & XAW_TPROP_FONT)
815		    font = property->font;
816		else
817		    font = sink->ascii_sink.font;
818		XSetForeground(XtDisplay(ctx), gc, property->background);
819	    }
820	    if (i_rects <= n_rects)
821		rects = (XRectangle*)
822		    XtRealloc((XtPointer)rects,	(Cardinal)(sizeof(XRectangle) *
823			      (size_t)++n_rects));
824	    rects[i_rects].x = (short)paint->x;
825	    rects[i_rects].y = (short)(paint->y - font->ascent);
826	    rects[i_rects].width = (unsigned short)paint->width;
827	    rects[i_rects++].height = (unsigned short)(font->ascent + font->descent);
828
829	    if (paint->backtabs) {
830		for (scan = paint->backtabs->scanline; scan && scan->next;
831		     scan = scan->next)
832		    for (seg = scan->segment; seg; seg = seg->next) {
833			if (i_rects <= n_rects)
834			    rects = (XRectangle*)
835				XtRealloc((XtPointer)rects, (Cardinal)(sizeof(XRectangle) *
836					  (size_t)++n_rects));
837			rects[i_rects].x = (short)seg->x1;
838			rects[i_rects].y = (short)scan->y;
839			rects[i_rects].width = (unsigned short)(seg->x2 - seg->x1);
840			rects[i_rects++].height = (unsigned short)(scan->next->y - scan->y);
841		    }
842	    }
843
844
845	}
846	paint = paint->next;
847    }
848    if (i_rects)
849	XFillRectangles(XtDisplay(ctx), XtWindow(ctx), gc, rects, i_rects);
850
851    paint = list->paint;
852    i_rects = 0;
853    while (paint) {
854	if (paint->highlight) {
855	    if (i_rects == 0)
856		XSetForeground(XtDisplay(ctx), gc, sink->text_sink.cursor_color);
857	    if (i_rects <= n_rects)
858		rects = (XRectangle*)
859		    XtRealloc((XtPointer)rects,	(Cardinal)(sizeof(XRectangle) *
860			      (size_t)++n_rects));
861	    rects[i_rects].x = (short)paint->x;
862	    rects[i_rects].y = (short)(paint->y - paint->max_ascent);
863	    rects[i_rects].width = (unsigned short)paint->width;
864	    rects[i_rects++].height = (unsigned short)(paint->max_ascent + paint->max_descent + 1);
865	}
866	paint = paint->next;
867    }
868    if (list->hightabs) {
869	for (scan = list->hightabs->scanline; scan && scan->next;
870	     scan = scan->next)
871	    for (seg = scan->segment; seg; seg = seg->next) {
872		if (i_rects == 0)
873		    XSetForeground(XtDisplay(ctx), gc,
874				   sink->text_sink.cursor_color);
875		if (i_rects <= n_rects)
876		    rects = (XRectangle*)
877			XtRealloc((XtPointer)rects, (Cardinal)(sizeof(XRectangle) *
878				  (size_t)++n_rects));
879		rects[i_rects].x = (short)seg->x1;
880		rects[i_rects].y = (short)scan->y;
881		rects[i_rects].width = (unsigned short)(seg->x2 - seg->x1);
882		rects[i_rects++].height = (unsigned short)(scan->next->y - scan->y);
883	    }
884    }
885
886    if (i_rects)
887	XFillRectangles(XtDisplay(ctx), XtWindow(ctx), gc, rects, i_rects);
888    if (rects)
889	XtFree((XtPointer)rects);
890
891    /* pass 5: draw text! */
892    paint = list->paint;
893    if (paint && (property = paint->property) == NULL) {
894	font = sink->ascii_sink.font;
895	XSetFont(XtDisplay(ctx), gc, font->fid);
896	if (!paint->highlight)
897	    XSetForeground(XtDisplay(ctx), gc, sink->text_sink.foreground);
898    }
899    else
900	property = NULL;
901    highlight = False;
902    while (paint) {
903	if (!highlight && paint->highlight)
904	    XSetForeground(XtDisplay(ctx), gc, sink->text_sink.background);
905	if (highlight || paint->highlight || paint->property != property) {
906	    if (!paint->property || !(paint->property->mask & XAW_TPROP_FONT))
907		font = sink->ascii_sink.font;
908	    else
909		font = paint->property->font;
910	    XSetFont(XtDisplay(ctx), gc, font->fid);
911	    if (!paint->highlight) {
912		if (!paint->property ||
913		    !(paint->property->mask & XAW_TPROP_FOREGROUND))
914		    XSetForeground(XtDisplay(ctx), gc,
915				   sink->text_sink.foreground);
916		else
917		    XSetForeground(XtDisplay(ctx), gc,
918				   paint->property->foreground);
919	    }
920	    highlight = paint->highlight;
921	    property = paint->property;
922	}
923
924	if (paint->x < XtWidth(ctx) && paint->x + paint->width > 0) {
925	    XDrawString(XtDisplay(ctx), XtWindow(ctx), gc, paint->x, paint->y,
926			paint->text, (int)paint->length);
927	    if (property) {
928		if (property->mask & XAW_TPROP_UNDERLINE) {
929		    if (line_width != property->underline_thickness) {
930			values.line_width = line_width =
931			    property->underline_thickness;
932			XChangeGC(XtDisplay(ctx), gc, GCLineWidth, &values);
933		    }
934
935		    XDrawLine(XtDisplay(ctx), XtWindow(ctx), gc, paint->x,
936			      paint->y + property->underline_position,
937			      paint->x + paint->width,
938			      paint->y + property->underline_position);
939		}
940		if (property->mask & XAW_TPROP_OVERSTRIKE) {
941		    if (line_width != property->underline_thickness) {
942			values.line_width = line_width =
943			    property->underline_thickness;
944			XChangeGC(XtDisplay(ctx), gc, GCLineWidth, &values);
945		    }
946
947		    XDrawLine(XtDisplay(ctx), XtWindow(ctx), gc, paint->x,
948			      paint->y - (font->ascent>>1) + (font->descent>>1),
949			      paint->x + paint->width,
950			      paint->y - (font->ascent>>1) + (font->descent>>1));
951		}
952	    }
953	}
954
955	paint = paint->next;
956    }
957
958    /* pass 6: bearing clipping */
959    /* dont care on order of drawing or caching of state (by now) */
960    paint = list->bearings;
961    while (paint) {
962	if (paint->highlight)
963	    XSetForeground(XtDisplay(ctx), gc, sink->text_sink.background);
964	if (!paint->property || !(paint->property->mask & XAW_TPROP_FONT))
965	    font = sink->ascii_sink.font;
966	else
967	    font = paint->property->font;
968	XSetFont(XtDisplay(ctx), gc, font->fid);
969	if (!paint->highlight) {
970	    if (!paint->property ||
971		!(paint->property->mask & XAW_TPROP_FOREGROUND))
972		XSetForeground(XtDisplay(ctx), gc, sink->text_sink.foreground);
973	    else
974		XSetForeground(XtDisplay(ctx), gc, paint->property->foreground);
975	}
976	if (paint->x < XtWidth(ctx) && paint->x + paint->width > 0) {
977	    XRectangle rect2 = {
978		.x = (short)(paint->x + paint->width),
979		.width = (unsigned short)(XawAbs(paint->width)),    /* more than enough */
980		.y = (short)(paint->y - font->ascent),
981		.height = (unsigned short)((paint->y - font->ascent) +
982					   font->ascent + font->descent)
983	    };
984	    XSetClipRectangles(XtDisplay((Widget)ctx), gc,
985			       0, 0, &rect2, 1, Unsorted);
986	    XDrawString(XtDisplay(ctx), XtWindow(ctx), gc, paint->x, paint->y,
987			paint->text, (int)paint->length);
988	}
989	paint = paint->next;
990    }
991}
992#endif
993
994/*
995 * Function:
996 *	PaintText
997 *
998 * Parameters:
999 *	w   - text sink object
1000 *	gc  - gc to paint text with
1001 *	x   - location to paint the text
1002 *	y   - ""
1003 *	buf - buffer and length of text to paint.
1004 *	len - ""
1005 *	clear_bg - clear background before drawing ?
1006 *
1007 * Description:
1008 *	Actually paints the text into the window.
1009 *
1010 * Returns:
1011 *	the width of the text painted
1012 */
1013static unsigned int
1014PaintText(Widget w, GC gc, int x, int y, char *buf, int len, Bool clear_bg)
1015{
1016    AsciiSinkObject sink = (AsciiSinkObject)w;
1017    TextWidget ctx = (TextWidget)XtParent(w);
1018    int width = XTextWidth(sink->ascii_sink.font, buf, len);
1019
1020    if ((x > XtWidth(ctx)) || width <= -x) /* Don't draw if we can't see it */
1021	return (unsigned)(width);
1022
1023    if (clear_bg) {
1024	_XawTextSinkClearToBackground(w, x, y - sink->ascii_sink.font->ascent,
1025				     (unsigned)width,
1026				     (unsigned)(sink->ascii_sink.font->ascent
1027				     + sink->ascii_sink.font->descent));
1028	XDrawString(XtDisplay(ctx), XtWindow(ctx), gc, x, y, buf, len);
1029    }
1030    else
1031	XDrawImageString(XtDisplay(ctx), XtWindow(ctx), gc, x, y, buf, len);
1032
1033    return (unsigned)(width);
1034}
1035
1036static void
1037DisplayText(Widget w, int x, int y,
1038	    XawTextPosition pos1, XawTextPosition pos2, Bool highlight)
1039{
1040    TextWidget ctx = (TextWidget)XtParent(w);
1041    AsciiSinkObject sink = (AsciiSinkObject)w;
1042    XFontStruct *font = sink->ascii_sink.font;
1043    Widget source = XawTextGetSource(XtParent(w));
1044    unsigned char buf[260];
1045    int j, k;
1046    XawTextBlock blk;
1047    GC gc, invgc, tabgc;
1048    int max_x;
1049    Bool clear_bg;
1050
1051    if (!sink->ascii_sink.echo || !ctx->text.lt.lines)
1052	return;
1053
1054    max_x = (int)XtWidth(ctx) - ctx->text.r_margin.right;
1055    clear_bg = !highlight && ctx->core.background_pixmap != XtUnspecifiedPixmap;
1056
1057    gc = highlight ? sink->ascii_sink.invgc : sink->ascii_sink.normgc;
1058    invgc = highlight ? sink->ascii_sink.normgc : sink->ascii_sink.invgc;
1059
1060    if (highlight && sink->ascii_sink.xorgc)
1061	tabgc = sink->ascii_sink.xorgc;
1062    else
1063	tabgc = invgc;
1064
1065    y += sink->ascii_sink.font->ascent;
1066    for (j = 0; pos1 < pos2;) {
1067	pos1 = XawTextSourceRead(source, pos1, &blk, (int)(pos2 - pos1));
1068	for (k = 0; k < blk.length; k++) {
1069	    if ((unsigned)j >= sizeof(buf) - 4) {	/* buffer full, dump the text */
1070		if ((x = (int)((unsigned)x + PaintText(w, gc, x, y, (char*)buf, j, clear_bg)))
1071		    >= max_x)
1072		    return;
1073		j = 0;
1074	    }
1075	    buf[j] = (unsigned char)blk.ptr[k];
1076	    if (buf[j] == XawLF)	/* line feeds ('\n') are not printed */
1077		continue;
1078
1079	    else if (buf[j] == '\t') {
1080		int width;
1081
1082		if (j != 0
1083		    && (x = (int)((unsigned)x + PaintText(w, gc, x, y, (char*)buf, j, clear_bg)))
1084		    >= max_x)
1085		    return;
1086
1087		if ((width = CharWidth(sink, font, x, '\t')) > -x) {
1088		    if (clear_bg)
1089			_XawTextSinkClearToBackground(w, x, y-font->ascent, (unsigned)width,
1090						      (unsigned)(font->ascent+font->descent));
1091		    else
1092			XFillRectangle(XtDisplayOfObject(w), XtWindowOfObject(w),
1093				       tabgc, x, y - font->ascent, (unsigned)width,
1094				       (unsigned)(font->ascent + font->descent));
1095		}
1096
1097		if ((x += width) >= max_x)
1098		    return;
1099
1100		j = -1;
1101	    }
1102	    else if ((buf[j] & 0177) < XawSP || buf[j] == 0177) {
1103		if (sink->ascii_sink.display_nonprinting) {
1104		    unsigned char c = buf[j];
1105
1106		    if (c > 0177) {
1107			buf[j++] = '\\';
1108			buf[j++] = (unsigned char)(((c >> 6) & 7) + '0');
1109			buf[j++] = (unsigned char)(((c >> 3) & 7) + '0');
1110			buf[j] = (unsigned char)((c & 7) + '0');
1111		    }
1112		    else {
1113			c |= 0100;
1114			buf[j++] = '^';
1115			buf[j] = c == 0177 ? '?' : c;
1116		    }
1117		}
1118		else
1119		  buf[j] = ' ';
1120	    }
1121	    j++;
1122	}
1123    }
1124
1125    if (j > 0)
1126	(void)PaintText(w, gc, x, y, (char*)buf, j, clear_bg);
1127}
1128
1129/*
1130 * Function:
1131 *	GetCursorBounds
1132 *
1133 * Parameters:
1134 *	w - text sink object
1135 *	rect - X rectangle to return the cursor bounds
1136 *
1137 * Description:
1138 *	Returns the size and location of the cursor.
1139 */
1140static void
1141GetCursorBounds(Widget w, XRectangle *rect)
1142{
1143    AsciiSinkObject sink = (AsciiSinkObject)w;
1144    XFontStruct *font = sink->ascii_sink.font;
1145    unsigned char ch;
1146#ifndef OLDXAW
1147    TextWidget ctx = (TextWidget)XtParent(w);
1148    XawTextBlock block;
1149    XawTextAnchor *anchor;
1150    XawTextEntity *entity;
1151    XawTextProperty *property;
1152
1153    if (XawTextSourceAnchorAndEntity(XawTextGetSource(XtParent(w)),
1154				     sink->ascii_sink.cursor_position,
1155				     &anchor, &entity)) {
1156	if ((property = XawTextSinkGetProperty((Widget)sink,
1157					       entity->property)) != NULL &&
1158	    (property->mask & XAW_TPROP_FONT))
1159	    font = property->font;
1160    }
1161    (void)XawTextSourceRead(XawTextGetSource((Widget)ctx),
1162			    ctx->text.insertPos, &block, 1);
1163    if (!block.length || block.ptr[0] == '\n' || block.ptr[0] == '\t')
1164	ch = ' ';
1165    else if ((*((unsigned char*)block.ptr) & 0177) < XawSP ||
1166	*(unsigned char*)block.ptr == 0177) {
1167	if (sink->ascii_sink.display_nonprinting)
1168	    ch = *((unsigned char*)block.ptr) > 0177 ? '\\' : '^';
1169	else
1170	    ch = ' ';
1171    }
1172    else
1173	ch = *(unsigned char*)block.ptr;
1174#else
1175    ch = ' ';
1176#endif
1177
1178    rect->width = (unsigned short)(CharWidth(sink, font, 0, ch));
1179    rect->height = (unsigned short)(font->descent + font->ascent + 1);
1180
1181    rect->x = sink->ascii_sink.cursor_x;
1182    rect->y = (short)(sink->ascii_sink.cursor_y - font->ascent);
1183}
1184
1185/* this function is required to support different fonts and correctly place
1186 * the cursor. There are better ways to calculate the base line, but there is
1187 * no place/code (yet) to store this information.
1188 */
1189static int
1190FindCursorY(TextWidget ctx, XawTextPosition position)
1191{
1192    int y, line, ascent;
1193    AsciiSinkObject sink = (AsciiSinkObject)ctx->text.sink;
1194#ifndef OLDXAW
1195    XawTextAnchor *anchor;
1196    XawTextEntity *entity;
1197    XawTextProperty *property;
1198    XawTextPosition left, right;
1199#endif
1200
1201    for (line = 0; line < ctx->text.lt.lines; line++)
1202	if (position < ctx->text.lt.info[line + 1].position)
1203	    break;
1204
1205    y = ctx->text.lt.info[line].y;
1206#ifndef OLDXAW
1207    ascent = 0;
1208    left = ctx->text.lt.info[line].position;
1209    right = ctx->text.lt.info[line + 1].position;
1210    right = XawMin(right, ctx->text.lastPos + 1);
1211    while (left < right) {
1212	if (XawTextSourceAnchorAndEntity(ctx->text.source, left,
1213					 &anchor, &entity)) {
1214	    if ((property = XawTextSinkGetProperty((Widget)sink,
1215						   entity->property)) != NULL &&
1216		(property->mask & XAW_TPROP_FONT))
1217		ascent = XawMax(property->font->ascent, ascent);
1218	    else
1219		ascent = XawMax(sink->ascii_sink.font->ascent, ascent);
1220	    left = anchor->position + entity->offset + entity->length;
1221	}
1222	else if (anchor) {
1223	    ascent = XawMax(sink->ascii_sink.font->ascent, ascent);
1224	    while (entity) {
1225		XawTextPosition tmp = anchor->position + entity->offset + entity->length;
1226
1227		if (tmp > left && tmp < right) {
1228		    left = tmp;
1229		    if ((property = XawTextSinkGetProperty((Widget)sink,
1230							   entity->property)) != NULL &&
1231			(property->mask & XAW_TPROP_FONT))
1232			ascent = XawMax(property->font->ascent, ascent);
1233		    else
1234			ascent = XawMax(sink->ascii_sink.font->ascent, ascent);
1235		}
1236		entity = entity->next;
1237	    }
1238	    if (entity == NULL)
1239		break;
1240	}
1241	else {
1242	    ascent = XawMax(sink->ascii_sink.font->ascent, ascent);
1243	    break;
1244	}
1245    }
1246    if (!ascent)
1247	ascent = sink->ascii_sink.font->ascent;
1248#else
1249    ascent = sink->ascii_sink.font->ascent;
1250#endif
1251
1252    return (y + ascent);
1253}
1254
1255static void
1256InsertCursor(Widget w, int x, int y, XawTextInsertState state)
1257{
1258    AsciiSinkObject sink = (AsciiSinkObject)w;
1259    XFontStruct *font = sink->ascii_sink.font;
1260    TextWidget ctx = (TextWidget)XtParent(w);
1261    XawTextPosition position = XawTextGetInsertionPoint((Widget)ctx);
1262    Boolean overflow = ((unsigned)x & 0xffff8000) != 0;
1263#ifndef OLDXAW
1264    XawTextAnchor *anchor;
1265    XawTextEntity *entity;
1266    XawTextProperty *property;
1267#endif
1268
1269    if (XtIsRealized((Widget)ctx)) {
1270	int fheight;
1271	XawTextBlock block;
1272	XawTextPosition selection_start, selection_end;
1273	Boolean has_selection;
1274
1275	if (!sink->ascii_sink.echo) {
1276	    if (sink->ascii_sink.laststate != state) {
1277		int width = CharWidth(sink, font, 0, ' ') - 1;
1278
1279		x = ctx->text.margin.left;
1280		y = ctx->text.margin.top;
1281		font = sink->ascii_sink.font;
1282		fheight = font->ascent + font->descent;
1283		if (state == XawisOn) {
1284		    if (ctx->text.hasfocus)
1285		    XFillRectangle(XtDisplay(ctx), XtWindow(ctx),
1286				   sink->ascii_sink.xorgc, x, y,
1287				   (unsigned)(width + 1), (unsigned)(fheight + 1));
1288		    else
1289			XDrawRectangle(XtDisplay(ctx), XtWindow(ctx),
1290				       sink->ascii_sink.xorgc, x, y,
1291				       (unsigned)width, (unsigned)fheight);
1292
1293		}
1294		else
1295		    _XawTextSinkClearToBackground(w, x, y,
1296						  (unsigned)(width + 1), (unsigned)(fheight + 1));
1297	    }
1298	    sink->ascii_sink.cursor_x = (short)x;
1299	    sink->ascii_sink.cursor_y = (short)y;
1300	    sink->ascii_sink.laststate = state;
1301	    return;
1302	}
1303
1304
1305	XawTextGetSelectionPos((Widget)ctx, &selection_start, &selection_end);
1306	has_selection = selection_start != selection_end;
1307
1308	if (sink->ascii_sink.laststate != state) {
1309	    unsigned char ch;
1310
1311#ifndef OLDXAW
1312	    if (XawTextSourceAnchorAndEntity(ctx->text.source,
1313					     position, &anchor, &entity) &&
1314		(property = XawTextSinkGetProperty((Widget)sink,
1315						   entity->property)) != NULL &&
1316		(property->mask & XAW_TPROP_FONT))
1317		font = property->font;
1318	    else
1319		font = sink->ascii_sink.font;
1320#endif
1321
1322	    fheight = font->ascent + font->descent;
1323	    (void)XawTextSourceRead(XawTextGetSource((Widget)ctx),
1324				    position, &block, 1);
1325	    if (!block.length || block.ptr[0] == '\n' || block.ptr[0] == '\t')
1326		ch = ' ';
1327	    else if ((*((unsigned char*)block.ptr) & 0177) < XawSP
1328		|| *(unsigned char*)block.ptr == 0177) {
1329		if (sink->ascii_sink.display_nonprinting)
1330		    ch = *((unsigned char*)block.ptr) > 0177 ? '\\' : '^';
1331		else
1332		    ch = ' ';
1333	    }
1334	    else
1335		ch = *(unsigned char*)block.ptr;
1336
1337	    y = FindCursorY(ctx, position);
1338	    if (ctx->text.hasfocus && !has_selection)
1339		XFillRectangle(XtDisplay(ctx), XtWindow(ctx),
1340			       sink->ascii_sink.xorgc, x, y - font->ascent,
1341			       (unsigned)CharWidth(sink, font, 0, ch),
1342			       (unsigned)(fheight + 1));
1343	    else
1344		XDrawRectangle(XtDisplay(ctx), XtWindow(ctx),
1345			       sink->ascii_sink.xorgc, x, y - font->ascent,
1346			       (unsigned)(CharWidth(sink, font, 0, ch) - 1),
1347			       (unsigned)fheight);
1348	}
1349    }
1350
1351    sink->ascii_sink.cursor_x = (short)(overflow ? -16384 : x);
1352    sink->ascii_sink.cursor_y = (short)y;
1353    sink->ascii_sink.laststate = state;
1354    sink->ascii_sink.cursor_position = position;
1355}
1356
1357/*
1358 * Given two positions, find the distance between them
1359 */
1360static void
1361FindDistance(Widget w, XawTextPosition fromPos, int fromx,
1362	     XawTextPosition toPos, int *resWidth,
1363	     XawTextPosition *resPos, int *resHeight)
1364{
1365#ifndef OLDXAW
1366    AsciiSinkObject sink = (AsciiSinkObject)w;
1367    TextWidget ctx = (TextWidget)XtParent(w);
1368    XFontStruct *font;
1369    Widget source = ctx->text.source;
1370    XawTextPosition idx, pos;
1371    unsigned char c;
1372    XawTextBlock blk;
1373    int i, rWidth, ascent = 0, descent = 0;
1374    XawTextAnchor *anchor;
1375    XawTextEntity *entity;
1376    XawTextProperty *property;
1377    Cardinal length;
1378    Bool done = False;
1379
1380    pos = idx = fromPos;
1381    rWidth = 0;
1382
1383    while (!done) {
1384	if (XawTextSourceAnchorAndEntity(source, pos, &anchor, &entity)) {
1385	    length = (Cardinal)(anchor->position + entity->offset + entity->length);
1386	    length = (Cardinal)(XawMin(toPos, length) - pos);
1387	    if ((property = XawTextSinkGetProperty((Widget)sink,
1388						   entity->property)) != NULL &&
1389		(property->mask & XAW_TPROP_FONT))
1390		font = property->font;
1391	    else
1392		font = sink->ascii_sink.font;
1393	}
1394	else {
1395	    if (anchor) {
1396		while (entity && anchor->position + entity->offset < pos)
1397		    entity = entity->next;
1398		if (entity) {
1399		    length = (Cardinal)(anchor->position + entity->offset);
1400		    length = (Cardinal)(XawMin(toPos, length) - pos);
1401		}
1402		else
1403		    length = (Cardinal)(XawMin(toPos - pos, 4096));
1404	    }
1405	    else
1406		length = (Cardinal)(XawMin(toPos - pos, 4096));
1407	    font = sink->ascii_sink.font;
1408	}
1409
1410	ascent = XawMax(font->ascent, ascent);
1411	descent = XawMax(font->descent, descent);
1412
1413	pos = XawTextSourceRead(source, pos, &blk, (int)length);
1414	if (blk.length == 0 && pos == idx)	/* eof reached */
1415	    break;
1416
1417	idx = blk.firstPos;
1418	for (i = 0; idx < toPos; i++, idx++) {
1419	    if (i >= blk.length)
1420		break;
1421	    c = (unsigned char)blk.ptr[i];
1422	    rWidth += CharWidth(sink, font, fromx + rWidth, c);
1423	    if (c == XawLF) {
1424		idx++;
1425		done = True;
1426		break;
1427	    }
1428	}
1429	if (idx >= toPos)
1430	    break;
1431    }
1432
1433    *resPos = idx;
1434    *resWidth = rWidth;
1435    *resHeight = ascent + descent + 1;
1436#else
1437    AsciiSinkObject sink = (AsciiSinkObject)w;
1438    TextWidget ctx = (TextWidget)XtParent(w);
1439    XFontStruct *font = sink->ascii_sink.font;
1440    Widget source = ctx->text.source;
1441    XawTextPosition idx, pos;
1442    XawTextBlock blk;
1443    int i, rWidth;
1444
1445    pos = XawTextSourceRead(source, fromPos, &blk, (int)(toPos - fromPos));
1446    rWidth = 0;
1447    for (i = 0, idx = fromPos; idx < toPos; i++, idx++) {
1448	unsigned char c;
1449
1450	if (i >= blk.length) {
1451	    i = 0;
1452	    pos = XawTextSourceRead(source, pos, &blk, (int)(toPos - pos));
1453	    if (blk.length == 0)
1454		break;
1455	}
1456	c = (unsigned char)blk.ptr[i];
1457	rWidth += CharWidth(sink, font, fromx + rWidth, c);
1458	if (c == XawLF) {
1459	    idx++;
1460	    break;
1461	}
1462    }
1463
1464    *resPos = idx;
1465    *resWidth = rWidth;
1466    *resHeight = font->ascent + font->descent + 1;
1467#endif
1468}
1469
1470static void
1471FindPosition(Widget w, XawTextPosition fromPos, int fromx, int width,
1472	     Bool stopAtWordBreak, XawTextPosition *resPos,
1473	     int *resWidth, int *resHeight)
1474{
1475#ifndef OLDXAW
1476    AsciiSinkObject sink = (AsciiSinkObject)w;
1477    TextWidget ctx = (TextWidget)XtParent(w);
1478    Widget source = ctx->text.source;
1479    XFontStruct *font;
1480    XawTextPosition idx, pos, whiteSpacePosition = 0;
1481    int i, lastWidth, whiteSpaceWidth, rWidth, ascent = 0, descent = 0;
1482    Boolean whiteSpaceSeen;
1483    unsigned char c;
1484    XawTextBlock blk;
1485    XawTextAnchor *anchor;
1486    XawTextEntity *entity;
1487    XawTextProperty *property;
1488    Cardinal length;
1489    Bool done = False;
1490
1491    pos = idx = fromPos;
1492    rWidth = lastWidth = whiteSpaceWidth = 0;
1493    whiteSpaceSeen = False;
1494    c = 0;
1495
1496    while (!done) {
1497	font = sink->ascii_sink.font;
1498	if (XawTextSourceAnchorAndEntity(source, pos, &anchor, &entity)) {
1499	    length = (Cardinal)(anchor->position + entity->offset + entity->length - pos);
1500	    if ((property = XawTextSinkGetProperty((Widget)sink,
1501						   entity->property)) != NULL &&
1502		(property->mask & XAW_TPROP_FONT))
1503		font = property->font;
1504	}
1505	else {
1506	    if (anchor) {
1507		while (entity && anchor->position + entity->offset < pos)
1508		    entity = entity->next;
1509		if (entity)
1510		    length = (Cardinal)(anchor->position + entity->offset - pos);
1511		else
1512		    length = 4096;
1513	    }
1514	    else
1515		length = 4096;
1516	}
1517
1518	ascent = XawMax(font->ascent, ascent);
1519	descent = XawMax(font->descent, descent);
1520
1521	pos = XawTextSourceRead(source, pos, &blk, (int)length);
1522	if (blk.length == 0 && pos == idx)	/* eof reached */
1523	    break;
1524
1525	idx = blk.firstPos;
1526	for (i = 0; rWidth <= width && i < blk.length; i++, idx++) {
1527	    c = (unsigned char)blk.ptr[i];
1528	    lastWidth = rWidth;
1529	    rWidth += CharWidth(sink, font, fromx + rWidth, c);
1530
1531	    if (c == XawLF) {
1532		idx++;
1533		done = True;
1534		break;
1535	    }
1536	    else if ((c == XawSP || c == XawTAB) && rWidth <= width) {
1537		whiteSpaceSeen = True;
1538		whiteSpacePosition = idx;
1539		whiteSpaceWidth = rWidth;
1540	    }
1541	}
1542	if (rWidth > width)
1543	    break;
1544    }
1545
1546    if (rWidth > width && idx > fromPos) {
1547	idx--;
1548	rWidth = lastWidth;
1549	if (stopAtWordBreak && whiteSpaceSeen) {
1550	    idx = whiteSpacePosition + 1;
1551	    rWidth = whiteSpaceWidth;
1552	}
1553    }
1554
1555    if (idx >= ctx->text.lastPos && c != XawLF)
1556	idx = ctx->text.lastPos + 1;
1557
1558    *resPos = idx;
1559    *resWidth = rWidth;
1560    *resHeight = ascent + descent + 1;
1561#else
1562    AsciiSinkObject sink = (AsciiSinkObject)w;
1563    TextWidget ctx = (TextWidget)XtParent(w);
1564    Widget source = ctx->text.source;
1565    XFontStruct *font = sink->ascii_sink.font;
1566    XawTextPosition idx, pos, whiteSpacePosition = 0;
1567    int i, lastWidth, whiteSpaceWidth, rWidth;
1568    Boolean whiteSpaceSeen;
1569    unsigned char c;
1570    XawTextBlock blk;
1571
1572    pos = XawTextSourceRead(source, fromPos, &blk, BUFSIZ);
1573    rWidth = lastWidth = whiteSpaceWidth = 0;
1574    whiteSpaceSeen = False;
1575    c = 0;
1576
1577    for (i = 0, idx = fromPos; rWidth <= width; i++, idx++) {
1578	if (i >= blk.length) {
1579	    i = 0;
1580	    pos = XawTextSourceRead(source, pos, &blk, BUFSIZ);
1581	    if (blk.length == 0)
1582		break;
1583	}
1584	c = (unsigned char)blk.ptr[i];
1585	lastWidth = rWidth;
1586	rWidth += CharWidth(sink, font, fromx + rWidth, c);
1587
1588	if (c == XawLF) {
1589	    idx++;
1590	    break;
1591	}
1592	else if ((c == XawSP || c == XawTAB) && rWidth <= width) {
1593	    whiteSpaceSeen = True;
1594	    whiteSpacePosition = idx;
1595	    whiteSpaceWidth = rWidth;
1596	}
1597    }
1598
1599    if (rWidth > width && idx > fromPos) {
1600	idx--;
1601	rWidth = lastWidth;
1602	if (stopAtWordBreak && whiteSpaceSeen) {
1603	    idx = whiteSpacePosition + 1;
1604	    rWidth = whiteSpaceWidth;
1605	}
1606    }
1607
1608    if (idx >= ctx->text.lastPos && c != XawLF)
1609	idx = ctx->text.lastPos + 1;
1610
1611    *resPos = idx;
1612    *resWidth = rWidth;
1613    *resHeight = font->ascent + font->descent + 1;
1614#endif
1615}
1616
1617static void
1618Resolve(Widget w, XawTextPosition pos, int fromx, int width,
1619	XawTextPosition *pos_return)
1620{
1621    int resWidth, resHeight;
1622    Widget source = XawTextGetSource(XtParent(w));
1623
1624    FindPosition(w, pos, fromx, width, False, pos_return, &resWidth, &resHeight);
1625    if (*pos_return > GETLASTPOS)
1626	*pos_return = GETLASTPOS;
1627}
1628
1629static void
1630GetGC(AsciiSinkObject sink)
1631{
1632    XtGCMask valuemask = (GCFont | GCGraphicsExposures | GCClipXOrigin |
1633			  GCForeground | GCBackground);
1634    XGCValues values = {
1635	/* XXX We dont want to share a gc that will change the clip-mask */
1636	.clip_x_origin = (int)(long)sink,
1637	.clip_mask = None,
1638	.font = sink->ascii_sink.font->fid,
1639	.graphics_exposures = False,
1640
1641	.foreground = sink->text_sink.foreground,
1642	.background = sink->text_sink.background
1643    };
1644    sink->ascii_sink.normgc = XtAllocateGC((Widget)sink, 0, valuemask, &values,
1645					   GCClipMask | GCFont | GCForeground |
1646					   GCBackground, 0);
1647
1648    values.foreground = sink->text_sink.background;
1649#ifndef OLDXAW
1650    values.background = sink->text_sink.cursor_color;
1651#else
1652    values.background = sink->text_sink.foreground;
1653#endif
1654    sink->ascii_sink.invgc = XtAllocateGC((Widget)sink, 0, valuemask, &values,
1655					  GCClipMask | GCFont, 0);
1656
1657    valuemask |= GCFunction;
1658    values.function = GXxor;
1659#ifndef OLDXAW
1660    values.foreground = sink->text_sink.background ^ sink->text_sink.cursor_color;
1661#else
1662    values.foreground = sink->text_sink.background ^ sink->text_sink.foreground;
1663#endif
1664    values.background = 0L;
1665    sink->ascii_sink.xorgc = XtAllocateGC((Widget)sink, 0, valuemask,
1666					  &values, GCClipMask | GCFont, 0);
1667
1668    XawAsciiSinkResize((Widget)sink);
1669}
1670
1671/* Function:
1672 *	XawAsciiSinkInitialize
1673 *
1674 * Parameters:
1675 *	request - the requested and new values for the object instance
1676 *	cnew	- ""
1677 *
1678 * Description:
1679 *	Initializes the TextSink Object.
1680 */
1681/*ARGSUSED*/
1682static void
1683XawAsciiSinkInitialize(Widget request _X_UNUSED, Widget cnew,
1684		       ArgList args _X_UNUSED, Cardinal *num_args _X_UNUSED)
1685{
1686    AsciiSinkObject sink = (AsciiSinkObject)cnew;
1687
1688    if (!sink->ascii_sink.font) XtError("Aborting: no font found\n");
1689
1690    GetGC(sink);
1691
1692    sink->ascii_sink.cursor_position = 0;
1693    sink->ascii_sink.laststate = XawisOff;
1694    sink->ascii_sink.cursor_x = sink->ascii_sink.cursor_y = 0;
1695}
1696
1697/*
1698 * Function:
1699 *	XawAsciiSinkDestroy
1700 *
1701 * Parameters:
1702 *	w - AsciiSink Object
1703 *
1704 * Description:
1705 *	This function cleans up when the object is destroyed.
1706 */
1707static void
1708XawAsciiSinkDestroy(Widget w)
1709{
1710    AsciiSinkObject sink = (AsciiSinkObject)w;
1711
1712    XtReleaseGC(w, sink->ascii_sink.normgc);
1713    XtReleaseGC(w, sink->ascii_sink.invgc);
1714    XtReleaseGC(w, sink->ascii_sink.xorgc);
1715
1716    sink->ascii_sink.normgc =
1717      sink->ascii_sink.invgc =
1718      sink->ascii_sink.xorgc = NULL;
1719}
1720
1721static void
1722XawAsciiSinkResize(Widget w)
1723{
1724    TextWidget ctx = (TextWidget)XtParent(w);
1725    AsciiSinkObject sink = (AsciiSinkObject)w;
1726    XRectangle rect;
1727    int width, height;
1728
1729    if (w->core.widget_class != asciiSinkObjectClass)
1730	return;
1731
1732    rect.x = ctx->text.r_margin.left;
1733    rect.y = ctx->text.r_margin.top;
1734    width = (int)XtWidth(ctx) - RHMargins(ctx);
1735    height = (int)XtHeight(ctx) - RVMargins(ctx);
1736    rect.width = (unsigned short)width;
1737    rect.height = (unsigned short)height;
1738
1739    if (sink->ascii_sink.normgc) {
1740	if (width >= 0 && height >= 0)
1741	    XSetClipRectangles(XtDisplay((Widget)ctx), sink->ascii_sink.normgc,
1742			       0, 0, &rect, 1, Unsorted);
1743	else
1744	    XSetClipMask(XtDisplay((Widget)ctx), sink->ascii_sink.normgc, None);
1745    }
1746    if (sink->ascii_sink.invgc) {
1747	if (width >= 0 && height >= 0)
1748	    XSetClipRectangles(XtDisplay((Widget)ctx), sink->ascii_sink.invgc,
1749			       0, 0, &rect, 1, Unsorted);
1750	else
1751	    XSetClipMask(XtDisplay((Widget)ctx), sink->ascii_sink.invgc, None);
1752    }
1753    if (sink->ascii_sink.xorgc) {
1754	if (width >= 0 && height >= 0)
1755	    XSetClipRectangles(XtDisplay((Widget)ctx), sink->ascii_sink.xorgc,
1756			       0, 0, &rect, 1, Unsorted);
1757	else
1758	    XSetClipMask(XtDisplay((Widget)ctx), sink->ascii_sink.xorgc, None);
1759    }
1760}
1761
1762/*
1763 * Function:
1764 *	XawAsciiSinkSetValues
1765 *
1766 * Parameters:
1767 *	current - current state of the object
1768 *	request - what was requested
1769 *	cnew    - what the object will become
1770 *
1771 * Description:
1772 *	Sets the values for the AsciiSink.
1773 *
1774 * Returns:
1775 *	True if redisplay is needed
1776 */
1777/*ARGSUSED*/
1778static Boolean
1779XawAsciiSinkSetValues(Widget current, Widget request _X_UNUSED, Widget cnew,
1780		      ArgList args _X_UNUSED, Cardinal *num_args _X_UNUSED)
1781{
1782    AsciiSinkObject w = (AsciiSinkObject)cnew;
1783    AsciiSinkObject old_w = (AsciiSinkObject)current;
1784
1785    if (w->ascii_sink.font != old_w->ascii_sink.font
1786	|| w->text_sink.background != old_w->text_sink.background
1787	|| w->text_sink.foreground != old_w->text_sink.foreground
1788#ifndef OLDXAW
1789	|| w->text_sink.cursor_color != old_w->text_sink.cursor_color
1790	|| w->text_sink.properties != old_w->text_sink.properties
1791#endif
1792	) {
1793#ifdef OLDXAW
1794	XtReleaseGC(cnew, w->ascii_sink.normgc);
1795	XtReleaseGC(cnew, w->ascii_sink.invgc);
1796	XtReleaseGC(cnew, w->ascii_sink.xorgc);
1797	GetGC(w);
1798#endif
1799	((TextWidget)XtParent(cnew))->text.redisplay_needed = True;
1800    }
1801    else if (w->ascii_sink.echo != old_w->ascii_sink.echo
1802	     || w->ascii_sink.display_nonprinting
1803	     != old_w->ascii_sink.display_nonprinting)
1804      ((TextWidget)XtParent(cnew))->text.redisplay_needed = True;
1805#ifndef OLDXAW
1806    if (w->text_sink.properties != old_w->text_sink.properties) {
1807	XawTextProperty *property =
1808	    XawTextSinkGetProperty(cnew, XrmStringToQuark("default"));
1809
1810	if (property) {
1811	    if (property->mask & XAW_TPROP_FONT)
1812		w->ascii_sink.font = property->font;
1813	    if (property->mask & XAW_TPROP_FOREGROUND)
1814		w->text_sink.foreground = property->foreground;
1815	    if (property->mask & XAW_TPROP_BACKGROUND)
1816		w->text_sink.background = property->background;
1817	}
1818    }
1819#endif
1820
1821    return (False);
1822}
1823
1824/*
1825 * Function:
1826 *	MaxLines
1827 *
1828 * Parameters:
1829 *	w      - AsciiSink Object
1830 *	height - height to fit lines into
1831 *
1832 * Description:
1833 *	Finds the Maximum number of lines that will fit in a given height.
1834 *
1835 * Returns:
1836 *	The number of lines that will fit
1837 */
1838/*ARGSUSED*/
1839static int
1840MaxLines(Widget w, unsigned int height)
1841{
1842    AsciiSinkObject sink = (AsciiSinkObject)w;
1843    int font_height;
1844
1845    font_height = sink->ascii_sink.font->ascent + sink->ascii_sink.font->descent + 1;
1846
1847    return ((int)height / font_height);
1848}
1849
1850/*
1851 * Function:
1852 *	MaxHeight
1853 *
1854 * Parameters:
1855 *	w     - AsciiSink Object
1856 *	lines - number of lines
1857 *
1858 * Description:
1859 *	Finds the Minimum height that will contain a given number lines.
1860 *
1861 * Returns:
1862 *	the height
1863 */
1864static int
1865MaxHeight(Widget w, int lines)
1866{
1867    AsciiSinkObject sink = (AsciiSinkObject)w;
1868
1869    return (lines * (sink->ascii_sink.font->ascent +
1870		     sink->ascii_sink.font->descent + 1));
1871}
1872
1873/*
1874 * Function:
1875 *	SetTabs
1876 *
1877 * Parameters:
1878 *	w	  - AsciiSink Object
1879 *	tab_count - number of tabs in the list
1880 *	tabs	  - text positions of the tabs
1881 *
1882 * Description:
1883 *	Sets the Tab stops.
1884 */
1885static void
1886SetTabs(Widget w, int tab_count, short *tabs)
1887{
1888    AsciiSinkObject sink = (AsciiSinkObject)w;
1889    int i;
1890    Atom XA_FIGURE_WIDTH;
1891    unsigned long figure_width = 0;
1892    XFontStruct *font = sink->ascii_sink.font;
1893
1894    /*
1895     * Find the figure width of the current font
1896     */
1897    XA_FIGURE_WIDTH = XInternAtom(XtDisplayOfObject(w), "FIGURE_WIDTH", False);
1898    if (XA_FIGURE_WIDTH != None
1899	&& (!XGetFontProperty(font, XA_FIGURE_WIDTH, &figure_width)
1900	    || figure_width == 0)) {
1901	if (font->per_char && font->min_char_or_byte2 <= '$'
1902	    && font->max_char_or_byte2 >= '$')
1903	    figure_width = (unsigned long)font->per_char['$' - font->min_char_or_byte2].width;
1904	else
1905	    figure_width = (unsigned long)font->max_bounds.width;
1906      }
1907
1908    if (tab_count > sink->text_sink.tab_count) {
1909	sink->text_sink.tabs = (Position *)
1910	  XtRealloc((char*)sink->text_sink.tabs, (Cardinal)((size_t)tab_count * sizeof(Position)));
1911	sink->text_sink.char_tabs = (short *)
1912	  XtRealloc((char*)sink->text_sink.char_tabs, (Cardinal)((size_t)tab_count * sizeof(short)));
1913    }
1914
1915    for (i = 0 ; i < tab_count ; i++) {
1916	sink->text_sink.tabs[i] = (Position)((size_t)tabs[i] * figure_width);
1917	sink->text_sink.char_tabs[i] = tabs[i];
1918      }
1919
1920    sink->text_sink.tab_count = tab_count;
1921
1922#ifndef NO_TAB_FIX
1923    {
1924	TextWidget ctx = (TextWidget)XtParent(w);
1925	ctx->text.redisplay_needed = True;
1926	_XawTextBuildLineTable(ctx, ctx->text.lt.top, True);
1927    }
1928#endif
1929}
1930